BFactory

BFactory deploys Baseline tokens and pools.

Overview

BFactory deploys new BToken instances and creates pools. Only the recorded bToken deployer may createPool for that bToken. Entry points:

  1. createBToken: deploy a minimal ERC-20 bToken and mint the total supply to the caller
  2. createPool: connect a bToken to a reserve, Uniswap v4 pool, BLV, fees, and optional initial credit (Merkle claim + collateral/debt) via CreateParams
  3. precomputeBTokenAddress: predict the create2 address of a bToken before deployment (salted per deployer)

createPool is payable for native-reserve funding; the Relay routes the shared component stack as for other Component calls.

Factory functions

createBToken

Deploys a new bToken. The full _totalSupply is transferred to msg.sender. The deployer is recorded in protocol state; only that address may call createPool for that bToken.

function createBToken(string memory _name, string memory _symbol, uint256 _totalSupply, bytes32 _salt) external returns (BToken bToken_)
ParameterTypeDescription
_namestringbToken name
_symbolstringbToken symbol
_totalSupplyuint256Full supply to mint to msg.sender (subject to on-chain min/max)
_saltbytes32Salt for create2; combined with msg.sender in the hash

Returns: BToken, the new bToken instance

createPool

CreateParams bundles bToken reference, pool reserves, active and BLV prices, creator, fee split, optional hook deployment, fee percentages, and optional initial credit (Merkle root, collateral, debt). The pool cannot already be initialized, and the caller must be the recorded deployer for params.bToken.

function createPool(CreateParams calldata params) public payable
ParameterTypeDescription
paramsCreateParamsBToken, reserve, initial liquidity, curve prices, fee split, optional hook, and optional initial credit fields

CreateParams

struct CreateParams {
    BToken bToken;
    uint256 initialPoolBTokens;
    address reserve;
    uint256 initialPoolReserves;
    uint256 initialActivePrice;
    uint256 initialBLV;
    address creator;
    address feeRecipient;
    uint256 creatorFeePct;
    uint256 swapFeePct;
    bool createHook;
    bytes32 claimMerkleRoot;
    uint256 initialCollateral;
    uint256 initialDebt;
}

Book price

Book price is useful for calculating initial pricing. It is the reserve backing per circulating bToken at launch: bookPrice = reserves / circ, where reserves = initialPoolReserves + initialDebt and circ = totalSupply - initialPoolBTokens.

FieldTypeDescription
bTokenBTokenThe bToken returned by createBToken. msg.sender must be the recorded deployer for this token.
initialPoolBTokensuint256bToken amount transferred from msg.sender into the pool as initial unsold supply. Must be less than the bToken total supply; otherwise initial circulating supply is zero and curve initialization cannot price the pool correctly.
reserveaddressApproved reserve token address. If funding with native ETH, this must be the configured wrapped native token.
initialPoolReservesuint256Reserve token amount transferred from msg.sender into the pool. For ERC-20 reserves, approve the Relay first. For native ETH funding, send this amount as msg.value; excess ETH is refunded.
initialActivePriceuint256Initial target active price in WAD precision. It must be greater than the pool's initial book price.
initialBLVuint256Initial/minimum BLV floor price in WAD precision. For normal deployers, createPool must initialize a standard quadratic curve; pass 0 to let the protocol compute the starting BLV for that quadratic curve. The resulting BLV must be less than or equal to book price.
creatoraddressNon-zero creator address recorded on the pool.
feeRecipientaddressNon-zero address that receives the creator share of fees.
creatorFeePctuint256WAD percentage of post-protocol fees paid to feeRecipient before staking fees. Must be <= 1e18; the remainder goes to staking.
swapFeePctuint256Minimum swap fee in WAD precision. Must be between 0.0015 ether (0.15%) and 0.5 ether (50%).
createHookboolIf true, initializes the Uniswap v4 hook pool for the bToken/reserve pair.
claimMerkleRootbytes32Merkle root for optional initial credit claims. Use bytes32(0) when not launching with initial credit. Must be approved to use.
initialCollateraluint256Optional bToken collateral reserved for initial credit. Must be zero unless claimMerkleRoot and initialDebt are both non-zero. Must be approved to use.
initialDebtuint256Optional reserve debt backing initial credit. Must be zero unless claimMerkleRoot and initialCollateral are both non-zero. When set, it is counted in initial total reserves. Must be approved to use.

claimMerkleRoot, initialCollateral, and initialDebt are all-or-nothing: either all are empty/zero, or the root is non-zero and both amounts are positive. Initial credit also requires the deployer profile to be active and approved for credit deployment, and the resulting position must be solvent.

createPool transfers initialPoolBTokens + initialCollateral bTokens from the caller and transfers initialPoolReserves reserve tokens from the caller. Approve those amounts before calling unless the reserve side is funded with native ETH.

precomputeBTokenAddress

Create2 address for the bToken that createBToken would deploy with the same name, symbol, total supply, salt, and deployer. Use the same _deployer you will use as msg.sender on createBToken.

function precomputeBTokenAddress(string memory _name, string memory _symbol, uint256 _totalSupply, bytes32 _salt, address _deployer) external view returns (address computedAddress_)
ParameterTypeDescription
_namestringMust match the planned createBToken call
_symbolstringMust match the planned createBToken call
_totalSupplyuint256Must match the planned createBToken call
_saltbytes32Must match the planned createBToken call
_deployeraddressAddress that will call createBToken (use msg.sender when you deploy)

Returns: address (computedAddress_): the address the bToken would have at that create2 address

Events

  • BTokenCreated: bToken address, name, symbol, decimals, total supply, creator.
  • PoolCreated: bToken, reserve, creator, fee recipient, fee and price parameters, pool id and capital totals (including initial credit when used).

Errors

ErrorDescription
NotDeployerCaller is not the recorded deployer for this bToken
NotApprovedReserveReserve token is not allowlisted for use
PoolAlreadyInitializedcreatePool called when a pool already exists for this bToken
TotalSupplyTooLowcreateBToken supply below the protocol minimum
TotalSupplyTooHighcreateBToken supply above the protocol maximum
InvalidNamebToken name fails validation
InvalidSymbolbToken symbol fails validation
InvalidFeeRecipientFee recipient address is invalid
InvalidCreatorCreator address or role is invalid
InvalidCreatorFeeCreator fee pct or related value is invalid
UnauthorizedCreditPositionCreationInitial credit setup is not permitted for this call
InvalidInitialCollateralOrDebtInitial credit collateral or debt is inconsistent
InsolventInitialCreditPositionInitial credit position would be insolvent
InvalidPoolSupplyPool bToken / reserve supply inputs are invalid
InvalidSaltSalt does not meet create2 / validation rules
InvalidConvexityExpConvexity exponent for the curve is out of range

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": "createBToken",
    "inputs": [
      {
        "name": "_name",
        "type": "string",
        "internalType": "string"
      },
      {
        "name": "_symbol",
        "type": "string",
        "internalType": "string"
      },
      {
        "name": "_totalSupply",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_salt",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [
      {
        "name": "bToken_",
        "type": "address",
        "internalType": "contract BToken"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "type": "function",
    "name": "createPool",
    "inputs": [
      {
        "name": "params",
        "type": "tuple",
        "internalType": "struct BFactory.CreateParams",
        "components": [
          {
            "name": "bToken",
            "type": "address",
            "internalType": "contract BToken"
          },
          {
            "name": "initialPoolBTokens",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "reserve",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "initialPoolReserves",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "initialActivePrice",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "initialBLV",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "creator",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "feeRecipient",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "creatorFeePct",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "swapFeePct",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "createHook",
            "type": "bool",
            "internalType": "bool"
          },
          {
            "name": "claimMerkleRoot",
            "type": "bytes32",
            "internalType": "bytes32"
          },
          {
            "name": "initialCollateral",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "initialDebt",
            "type": "uint256",
            "internalType": "uint256"
          }
        ]
      }
    ],
    "outputs": [],
    "stateMutability": "payable"
  },
  {
    "type": "function",
    "name": "precomputeBTokenAddress",
    "inputs": [
      {
        "name": "_name",
        "type": "string",
        "internalType": "string"
      },
      {
        "name": "_symbol",
        "type": "string",
        "internalType": "string"
      },
      {
        "name": "_totalSupply",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_salt",
        "type": "bytes32",
        "internalType": "bytes32"
      },
      {
        "name": "_deployer",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "computedAddress_",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "function",
    "name": "supportsInterface",
    "inputs": [
      {
        "name": "_interfaceId",
        "type": "bytes4",
        "internalType": "bytes4"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "pure"
  },
  {
    "type": "event",
    "name": "BTokenCreated",
    "inputs": [
      {
        "name": "bTokenAddress",
        "type": "address",
        "indexed": false,
        "internalType": "contract BToken"
      },
      {
        "name": "name",
        "type": "string",
        "indexed": false,
        "internalType": "string"
      },
      {
        "name": "symbol",
        "type": "string",
        "indexed": false,
        "internalType": "string"
      },
      {
        "name": "decimals",
        "type": "uint8",
        "indexed": false,
        "internalType": "uint8"
      },
      {
        "name": "totalSupply",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "creator",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "Initialized",
    "inputs": [
      {
        "name": "bToken",
        "type": "address",
        "indexed": false,
        "internalType": "contract BToken"
      },
      {
        "name": "activePrice",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "blvPrice",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "swapFeePct",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "type": "event",
    "name": "PoolCreated",
    "inputs": [
      {
        "name": "bTokenAddress",
        "type": "address",
        "indexed": false,
        "internalType": "contract BToken"
      },
      {
        "name": "reserveAddress",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "creator",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "feeRecipient",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "creatorFeePct",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "initialActivePrice",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "initialBlvPrice",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "totalReserves",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "totalBTokens",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "totalCollateral",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "totalDebt",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "poolId",
        "type": "bytes32",
        "indexed": false,
        "internalType": "bytes32"
      }
    ],
    "anonymous": false
  },
  {
    "type": "error",
    "name": "AlreadyInitialized",
    "inputs": []
  },
  {
    "type": "error",
    "name": "Component_NotPermitted",
    "inputs": []
  },
  {
    "type": "error",
    "name": "GuardLib_Paused",
    "inputs": []
  },
  {
    "type": "error",
    "name": "GuardLib_Reentrant",
    "inputs": []
  },
  {
    "type": "error",
    "name": "GuardLib_ReserveAccountingMismatch",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InsolventInitialCreditPosition",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidActivePrice",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidBLVPrice",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidConvexityExp",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidConvexityExp",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidCreator",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidCreatorFee",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidFeeRecipient",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidInitialCollateralOrDebt",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidName",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidPoolSupply",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidSalt",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidSwapFeePct",
    "inputs": []
  },
  {
    "type": "error",
    "name": "InvalidSymbol",
    "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": "NotApprovedReserve",
    "inputs": []
  },
  {
    "type": "error",
    "name": "NotDeployer",
    "inputs": []
  },
  {
    "type": "error",
    "name": "PoolAlreadyInitialized",
    "inputs": []
  },
  {
    "type": "error",
    "name": "TotalSupplyTooHigh",
    "inputs": []
  },
  {
    "type": "error",
    "name": "TotalSupplyTooLow",
    "inputs": []
  },
  {
    "type": "error",
    "name": "UnauthorizedCreditPositionCreation",
    "inputs": []
  }
]