BSwap

BSwap is the Mercury AMM for bTokens on Ethereum, with n=2 power-law curve, exact in/out trades, quotes, fees, events, errors, and full JSON ABI for viem, ethers, and integrations.

Overview

The BSwap contract implements Baseline's power-law AMM curve for token trading, handling all buy and sell operations with the n=2 curve and BLV translation.

Functions

Trading Functions

buyTokensExactIn

Buy bTokens with an exact amount of reserves.

function buyTokensExactIn(
  BToken _bToken,
  uint256 _amountIn,
  uint256 _limitAmount
) external returns (uint256 amountOut_, uint256 feesReceived_)
ParameterTypeDescription
_bTokenBTokenThe bToken to buy
_amountInuint256Exact reserve amount to spend
_limitAmountuint256Minimum bTokens to receive (slippage protection)

Returns:

  • amountOut_: bTokens received
  • feesReceived_: Fees attributed to the trade

buyTokensExactOut

Buy an exact amount of bTokens.

function buyTokensExactOut(
  BToken _bToken,
  uint256 _amountOut,
  uint256 _limitAmount
) external returns (uint256 amountIn_, uint256 feesReceived_)
ParameterTypeDescription
_bTokenBTokenThe bToken to buy
_amountOutuint256Exact bTokens to receive
_limitAmountuint256Maximum reserves to spend (slippage protection)

Returns:

  • amountIn_: Reserves spent
  • feesReceived_: Fees attributed to the trade

sellTokensExactIn

Sell an exact amount of bTokens.

function sellTokensExactIn(
  BToken _bToken,
  uint256 _amountIn,
  uint256 _limitAmount
) external returns (uint256 amountOut_, uint256 feesReceived_)
ParameterTypeDescription
_bTokenBTokenThe bToken to sell
_amountInuint256Exact bTokens to sell
_limitAmountuint256Minimum reserves to receive (slippage protection)

Returns:

  • amountOut_: Reserves received
  • feesReceived_: Fees attributed to the trade

sellTokensExactOut

Sell bTokens to receive an exact amount of reserves.

function sellTokensExactOut(
  BToken _bToken,
  uint256 _amountOut,
  uint256 _limitAmount
) external returns (uint256 amountIn_, uint256 feesReceived_)
ParameterTypeDescription
_bTokenBTokenThe bToken to sell
_amountOutuint256Exact reserves to receive
_limitAmountuint256Maximum bTokens to sell (slippage protection)

Returns:

  • amountIn_: bTokens sold
  • feesReceived_: Fees attributed to the trade

Quote Functions

Quote functions return expected trade results without executing.

quoteBuyExactIn

function quoteBuyExactIn(BToken _bToken, uint256 _amountIn)
  external view returns (uint256 amountOut_, uint256 fee_)

Returns:

  • amountOut_: bTokens for _amountIn reserve (preview)
  • fee_: Fee portion of the quote

quoteBuyExactOut

function quoteBuyExactOut(BToken _bToken, uint256 _amountOut)
  external view returns (uint256 amountIn_, uint256 fee_)

Returns:

  • amountIn_: Reserves required for _amountOut bTokens (preview)
  • fee_: Fee portion of the quote

quoteSellExactIn

function quoteSellExactIn(BToken _bToken, uint256 _amountIn)
  external view returns (uint256 amountOut_, uint256 fee_)

Returns:

  • amountOut_: Reserves for _amountIn bTokens sold (preview)
  • fee_: Fee portion of the quote

quoteSellExactOut

function quoteSellExactOut(BToken _bToken, uint256 _amountOut)
  external view returns (uint256 amountIn_, uint256 fee_)

Returns:

  • amountIn_: bTokens to sell to receive _amountOut reserves (preview)
  • fee_: Fee portion of the quote

View Functions

getCurveParams

Get current curve parameters for a bToken.

function getCurveParams(BToken _bToken) external view returns (CurveParams memory)

Returns: CurveParams (CurveLib, WAD):

  • BLV, circ, supply, swapFee, reserves, totalSupply, convexityExp, lastInvariant (curve state for pricing and invariant math)

Events

event Swap(BToken bToken, address sender, bool isBuy, uint256 amountIn, uint256 amountOut, uint256 fee);

Errors

ErrorDescription
SlippageExceededResult would break the min/max slippage bound on the trade (_limitAmount)
SolverFailedNumerical solver failed to converge for the trade

Efficient Swap Paths For Integrators

BSwap exposes 4 swap functions, but only 2 are gas-efficient on-chain:

FunctionDirectionGasReason
buyTokensExactOutreserve → bTokenCheapDirect curve computation
sellTokensExactInbToken → reserveCheapDirect curve computation
buyTokensExactInreserve → bTokenExpensiveBinary-searches for amountOut
sellTokensExactOutbToken → reserveExpensiveBinary-searches for amountIn

The ExactIn/ExactOut naming refers to what's "exact" from the user's perspective — but the on-chain cost depends on whether the contract receives the "natural" input to the curve math (direct computation) or the other side (binary search).

Pattern for integrators:

  • Buys: Quote off-chain via quoteBuyExactIn (view call, solver is free), then execute via buyTokensExactOut with the quoted amountOut.
  • Sells: Call sellTokensExactIn directly — it's already the efficient path.
  • Never call buyTokensExactIn or sellTokensExactOut on-chain unless you can't pre-compute the amounts.

Usage Example

Recommended buy flow — quote off-chain, then execute on the cheap path:

// 1. Quote off-chain: how many bTokens does 100 reserves buy?
(uint256 quotedOut, uint256 quotedFee) = bswap.quoteBuyExactIn(
  bToken,
  100e18    // 100 reserves in
);

// 2. Execute via buyTokensExactOut with the quoted amount.
//    Apply slippage tolerance to the reserve cap (e.g. +1%).
uint256 maxIn = 101e18;
(uint256 amountIn, uint256 fees) = bswap.buyTokensExactOut(
  bToken,
  quotedOut,
  maxIn
);

// Sells are already on the efficient path — call directly.
(uint256 amountOut, uint256 sellFees) = bswap.sellTokensExactIn(
  bToken,
  10e18,    // 10 bTokens in
  9e18      // min 9 reserves out (slippage)
);

ABI

[
  {
    "type": "function",
    "name": "LABEL",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "pure"
  },
  {
    "type": "function",
    "name": "ROUTES",
    "inputs": [],
    "outputs": [
      {
        "name": "routes_",
        "type": "bytes4[]",
        "internalType": "bytes4[]"
      }
    ],
    "stateMutability": "pure"
  },
  {
    "type": "function",
    "name": "VERSION",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "pure"
  },
  {
    "type": "function",
    "name": "buyTokensExactIn",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_amountIn",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_limitAmount",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "amountOut_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "feesReceived_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "buyTokensExactOut",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_amountOut",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_limitAmount",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "amountIn_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "feesReceived_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "payable"
  },
  {
    "type": "function",
    "name": "getCurveParams",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "tuple",
        "internalType": "struct CurveParams",
        "components": [
          {
            "name": "BLV",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "circ",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "supply",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "swapFee",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "reserves",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "totalSupply",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "convexityExp",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "lastInvariant",
            "type": "uint256",
            "internalType": "uint256"
          }
        ]
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "quoteBuyExactIn",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_reservesIn",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "tokensOut_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "feesReceived_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "slippage_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "quoteBuyExactOut",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_amountOut",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "amountIn_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "feesReceived_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "slippage_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "quoteSellExactIn",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_amountIn",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "amountOut_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "feesReceived_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "slippage_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "quoteSellExactOut",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_reservesOut",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "tokensIn_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "feesReceived_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "slippage_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "sellTokensExactIn",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_amountIn",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_limitAmount",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "amountOut_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "feesReceived_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "sellTokensExactOut",
    "inputs": [
      {
        "name": "_bToken",
        "type": "address",
        "internalType": "contract BToken"
      },
      {
        "name": "_amountOut",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_limitAmount",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "amountIn_",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "feesReceived_",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "supportsInterface",
    "inputs": [
      {
        "name": "_interfaceId",
        "type": "bytes4",
        "internalType": "bytes4"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "pure"
  },
  {
    "type": "event",
    "name": "Distributed",
    "inputs": [
      {
        "name": "bToken",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "reserve",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "totalAmount",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "protocolFee",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "creatorFee",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "stakingFee",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "Swap",
    "inputs": [
      {
        "name": "bToken",
        "type": "address",
        "indexed": false,
        "internalType": "contract BToken"
      },
      {
        "name": "user",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "activePrice",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "blvPrice",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "bTokenDelta",
        "type": "int256",
        "indexed": false,
        "internalType": "int256"
      },
      {
        "name": "reserveDelta",
        "type": "int256",
        "indexed": false,
        "internalType": "int256"
      },
      {
        "name": "totalFee",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "liquidityFee",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "type": "error",
    "name": "Component_NotPermitted",
    "inputs": []
  },
  {
    "type": "error",
    "name": "GuardLib_Insolvent",
    "inputs": []
  },
  {
    "type": "error",
    "name": "GuardLib_Paused",
    "inputs": []
  },
  {
    "type": "error",
    "name": "GuardLib_Reentrant",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidConvexityExp",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidOutput",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidParameters",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidSwapDirection",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvariantDecreased",
    "inputs": [
      {
        "name": "prevInvariant",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "newInvariant",
        "type": "uint256",
        "internalType": "uint256"
      }
    ]
  },
  {
    "type": "error",
    "name": "NativeLib_AmountMismatch",
    "inputs": []
  },
  {
    "type": "error",
    "name": "NativeLib_NotWrapped",
    "inputs": []
  },
  {
    "type": "error",
    "name": "PriceMustChange",
    "inputs": []
  },
  {
    "type": "error",
    "name": "SlippageExceeded",
    "inputs": []
  },
  {
    "type": "error",
    "name": "SolverFailed",
    "inputs": []
  },
  {
    "type": "error",
    "name": "TradeExceedsLimit",
    "inputs": []
  }
]