Skip to main content
Custom Hooks inject additional logic into the swap execution flow without modifying core pool contracts. The PricingHookV3 intercepts swaps before and after Balancer vault execution, enabling dynamic pricing adjustments, after-hours spreads, and slippage monitoring.

Hook Execution Flow

Every swap triggers two hook calls: beforeSwap runs after oracle validation but before vault execution, and afterSwap runs after swap completion with actual output amounts. Hooks can modify execution parameters, reject swaps by reverting, or record execution data for monitoring. All hook operations execute within the same transaction as the swap itself—either everything succeeds or everything reverts.

Before Swap Hook

The beforeSwap function receives swap details and oracle price, returning adjusted execution price and expected output amount. Use this for after-hours spread application, dynamic fee adjustment, or custom pricing logic.
function beforeSwap(
    bytes32 poolId,
    bytes32 assetId,
    address tokenIn,
    uint256 amountIn,
    uint256 oraclePrice
) external returns (
    uint256 executionPrice,
    uint256 expectedOut
);
The hook stores execution context including pre-swap price, expected output, and calculated slippage for later validation in afterSwap. This enables verification that actual execution matched predicted outcomes.

After Swap Hook

The afterSwap function receives actual output amounts after vault execution, enabling post-execution validation and monitoring. Compare actual outputs against expected amounts to detect excessive slippage or pricing anomalies.
The hook calculates realized slippage by comparing expected versus actual output:
function afterSwap(poolId: string, actualOut: bigint) {
    const context = executionContexts[poolId];
    const expectedOut = context.expectedOut;
    
    // Calculate deviation percentage
    const slippage = expectedOut > actualOut
        ? ((expectedOut - actualOut) * 10000n) / expectedOut
        : ((actualOut - expectedOut) * 10000n) / expectedOut;
    
    // Check against pool-specific or default threshold
    const maxSlippage = poolMaxSlippage[poolId] || defaultMaxSlippage;
    
    if (slippage > maxSlippage) {
        emit SlippageExceeded(poolId, expectedOut, actualOut, slippage);
        // Log for monitoring but don't revert - swap already executed
    }
    
    // Store for analytics
    context.actualOut = actualOut;
    context.slippage = slippage;
}
Unlike beforeSwap, this function cannot revert the swap since tokens already transferred. Instead, emit events for monitoring systems to detect unusual execution patterns.

After-Hours Spreads

Apply additional spreads when trading occurs outside traditional market hours (14:00-21:00 UTC for US markets). This compensates liquidity providers for increased risk when external price discovery mechanisms are inactive.
Time PeriodMarket StatusSpread Applied
14:00-21:00 UTC, Mon-FriMarket Open0 bps (oracle price)
21:00-14:00 UTC, Mon-FriAfter Hours25-100 bps configurable
Saturday-SundayWeekend50-150 bps configurable
Exchange HolidaysClosed50-150 bps configurable
Configure spreads through the setAfterHoursSpread function with values in basis points. Higher spreads during low-liquidity periods protect providers from adverse selection while maintaining trading availability.
// POST https://api.trusset.org/v1/trading/hooks/configure

await fetch('https://api.trusset.org/v1/trading/hooks/configure', {
  method: 'POST',
  body: JSON.stringify({
    hookAddress: "0xPricingHookV3",
    afterHoursSpreadBps: 50, // 0.5%
    weekendSpreadBps: 100    // 1.0%
  })
});

Pool-Specific Configuration

Configure different slippage thresholds and pricing rules per pool to accommodate varying liquidity profiles and volatility characteristics.
setMaxSlippage
function
Configure maximum acceptable slippage for specific pool, overriding default threshold
setPoolPricingRule
function
Apply custom pricing logic to individual pools (e.g., different after-hours spreads)
disableHookForPool
function
Exclude specific pools from hook execution, falling back to standard oracle pricing
Pools with deeper liquidity may use tighter slippage thresholds (25-50 bps) while illiquid pools require wider tolerances (100-200 bps) to prevent excessive failed transactions.

Execution Context Storage

Hooks maintain execution state in memory between beforeSwap and afterSwap calls, storing expected outcomes for later comparison.
poolId
bytes32
Pool identifier linking pre-swap and post-swap contexts
assetId
bytes32
Asset identifier (ISIN) for price feed lookup
preSwapPrice
uint256
Oracle price at execution time, before any spread adjustments
expectedOut
uint256
Calculated output amount based on oracle price and pool state
actualOut
uint256
Actual received amount after Balancer vault execution
slippage
uint256
Calculated deviation between expected and actual output in basis points
Context storage enables post-execution analytics and monitoring. Track which pools experience consistent slippage, identify pricing inefficiencies, or detect potential manipulation attempts.

Custom Hook Development

Deploy your own hooks implementing the IPricingHookV3 interface for specialized pricing logic. Common use cases include:
  • Dynamic fee adjustment based on volatility or time of day
  • Circuit breakers that halt trading during extreme price movements
  • MEV protection through price impact limits or randomized execution
  • Compliance checks validating additional rules beyond token-level restrictions
  • Analytics recording for trade surveillance and market monitoring
Hooks execute within the swap transaction and can consume significant gas. Complex logic or expensive storage operations may cause transactions to fail due to block gas limits. Test thoroughly before production deployment.
Set hooks through the PoolManagerV3 contract using the setPricingHook function. This routes through timelock governance to prevent immediate changes that could disrupt active pools.