Bush Contract Registry
Overview
The Bush Contract Registry (BushContractRegistry) is the onchain source of truth for official Bush contracts. It keeps the canonical list of trusted routers, pool factories, hooks, and ERC4626 wrappers, so you can discover and validate protocol contracts on every supported network.
Pool factories carry extra metadata (their pool type and hook configuration). This lets aggregators, solvers, indexers, and onchain integrations answer two more questions:
- Which factories are official, and what do they deploy? See
getAllPoolFactoriesandgetPoolFactoriesByType. - Did an official factory deploy this pool? If so, what type is it and what hook does it have? See
getFactoryForPoolandisPoolFromRegisteredFactory.
The registry address is on the Deployment Addresses page, under Peripherals (deployment task 20260923-v3-contract-registry-v2). The ABI is on the Bush Contract Registry ABI page.
Purpose
The registry enables:
- Router Validation: Verify trusted routers before allowing transactions with the Vault
- Pool Validation: Check that an official factory deployed a pool, and find its pool type and hook
- Contract Discovery: Query deployed pool factories, their pool types, and their deployment status
- Alias Management: Use human-readable names instead of addresses
- Integration Safety: Ensure applications only interact with authorized contracts
Contract Types
The registry categorizes contracts into the following types:
| Type | Value | Description |
|---|---|---|
OTHER | 0 | Unspecified contract type (catch-all for helper contracts, etc.) |
POOL_FACTORY | 1 | Factory contracts that deploy pools |
ROUTER | 2 | Router contracts for swaps and liquidity operations |
HOOK | 3 | Hook contracts for custom pool behavior |
ERC4626 | 4 | ERC4626 wrapper contracts (restricted to wrappers known to be compatible) |
Each contract is registered under a unique name and address, and has exactly one type. Governance registers pool factories with registerPoolFactory, which records their metadata. registerBushContract rejects POOL_FACTORY with UseRegisterPoolFactory. Every contract type uses the same functions for deprecation, deregistration, and aliases.
Lifecycle Semantics
Deregistration and deprecation mean different things, so consumers need to understand all three states:
| State | Meaning |
|---|---|
| Registered + active | The contract is trusted. A factory in this state may still create new pools. |
Registered + deprecated (isActive == false) | The contract has been superseded. A deprecated factory should not be used to create new pools. Pools it already deployed are still valid, official pools. Deprecation does not mean you should stop routing through existing pools. It mirrors calling disable() on the factory. |
Not registered (isRegistered == false) | The contract is not, or is no longer, trusted. Governance uses deregistration to correct mistakes and to revoke trust in an unsafe contract. Pools from a deregistered factory no longer resolve via getFactoryForPool. |
Contract Aliases
Aliases are friendly names for common contracts. The aliases below are illustrative. Governance can change an alias target at any time, for example when moving to a new pool version such as LBP V3 to V4.
To get the current target, query the registry onchain with getBushContract(type, alias). For factories, you can also use getPoolFactory(alias).
| Alias | Type | Target |
|---|---|---|
WeightedPool | POOL_FACTORY | WeightedPoolFactory |
StablePool | POOL_FACTORY | StablePoolFactory |
Router | ROUTER | Router v2 |
BatchRouter | ROUTER | BatchRouter |
Pool Factory Metadata
Hook Modes
Each registered factory has a HookMode, which describes how it attaches hooks to the pools it deploys:
| Mode | Value | Meaning |
|---|---|---|
NONE | 0 | The factory always deploys pools without a hook. |
OPTIONAL | 1 | The factory accepts a hook address at pool creation time, and the address may be zero. The pool creator decides whether the pool has a hook. |
SPECIFIC | 2 | The factory attaches the same hook to every pool it deploys (for example, StableSurgePoolFactory). The registry stores this hook address with the factory. |
A pool from an OPTIONAL factory may or may not have a hook. To find out, read the hook from the Vault with IVault.getHooksConfig(pool).hooksContract. A pool from a SPECIFIC factory always has the registered hook.
Data Structures
ContractInfo: the stored state for any registered contract:
| Field | Type | Description |
|---|---|---|
contractType | ContractType | The type of contract. |
isRegistered | bool | Whether there is an entry for the associated address. |
isActive | bool | If registered, whether it is active or deprecated. |
FactoryInfo: the registry's stored state for a pool factory. isRegistered and isActive match the factory's ContractInfo:
| Field | Type | Description |
|---|---|---|
name | string | The factory's name, usually the deployment task id (e.g. "20260803-v3-weighted-pool"). |
poolType | string | The type of pool deployed by this factory (e.g. "WEIGHTED", "STABLE"). Free-form and case-sensitive. |
hookMode | HookMode | Whether pools from this factory have no hook, an optional hook, or a specific hook. |
hook | address | The hook attached to every pool from this factory (zero unless hookMode is SPECIFIC). |
isRegistered | bool | Whether there is an entry for the associated address. |
isActive | bool | If registered, whether it is active or deprecated. |
FactoryDetails: FactoryInfo plus live data read from the factory itself (via IVersion, IPoolVersion, and IBasePoolFactory). Use it to get everything about a factory in one call:
| Field | Type | Description |
|---|---|---|
factory | address | The address of the factory (zero if not registered). |
info | FactoryInfo | The registry's stored information about the factory. |
factoryVersion | string | The factory's own version string (IVersion.version()). |
poolVersion | string | The version string of pools deployed by this factory (IPoolVersion.getPoolVersion()). |
isDisabled | bool | Whether the factory has been disabled onchain (IBasePoolFactory.isDisabled()). A disabled factory can never create new pools. |
poolCount | uint256 | The number of pools the factory has deployed. Use it to page through getPoolsInRange on the factory. |
The registry stores only info. The other FactoryDetails fields are read from the factory on each call, so they always show its current state. If a factory doesn't support one of these calls, the field is left blank (an empty string, false, or 0).
Query Functions
Contract queries
| Function | Returns |
|---|---|
isTrustedRouter(router) | true if the address is an active ROUTER. |
isActiveBushContract(contractType, contractAddress) | true if the address is a registered, active contract of that type. |
getBushContract(contractType, name) | The address for a name or alias, and whether it is active. |
getBushContractInfo(contractAddress) | The ContractInfo for an address. |
Factory queries
| Function | Returns |
|---|---|
isActivePoolFactory(factory) | true if the address is a registered, active factory. |
isActivePoolFactoryOfType(poolType, factory) | true if the address is a registered, active factory of that pool type. |
isRegisteredPoolFactory(factory) | true if the address is a registered factory (active or deprecated). |
getPoolFactory(name) | The factory address and FactoryInfo for a name or alias. |
getPoolFactoryInfo(factory) | The FactoryInfo for a factory address. |
getPoolFactoryHook(factory) | The factory's hook (zero unless SPECIFIC). |
getPoolFactoryDetails(factory) | The FactoryDetails for a factory address. |
Pool queries
These functions loop over every registered factory, so they are intended for offchain use. To validate a pool onchain, see Verify a pool came from an official factory.
| Function | Returns |
|---|---|
getFactoryForPool(pool) | The registered factory that deployed the pool, and its FactoryInfo (zero / blank if none). |
getFactoryDetailsForPool(pool) | The FactoryDetails of the factory that deployed the pool. |
isPoolFromRegisteredFactory(pool) | true if any registered factory (active or deprecated) deployed the pool. |
isPoolOfType(poolType, pool) | true if a registered factory of that pool type deployed the pool. |
Factory enumeration
| Function | Returns |
|---|---|
getPoolFactoryCount() / getPoolFactoryAt(index) | Indexed access to registered factories. The order can change when a factory is deregistered. |
getPoolFactories() | All registered factory addresses, including deprecated ones. |
getAllPoolFactories() | All registered factory addresses and their FactoryInfo, including deprecated ones. |
getAllPoolFactoryDetails() | FactoryDetails for every registered factory. This makes several external calls per factory, so it is intended for offchain use. |
getPoolFactoriesByType(poolType, activeOnly) | Factory addresses of a given pool type, optionally excluding deprecated ones. |
Usage Examples
Validate a Router
Check if a router address is trusted before allowing transactions:
// In your smart contract
IBushContractRegistry registry = IBushContractRegistry(REGISTRY_ADDRESS);
function executeSwap(address router, SwapParams calldata params) external {
require(registry.isTrustedRouter(router), "Untrusted router");
// Execute swap...
}
Verify a pool came from an official factory
The pool queries (getFactoryForPool, getFactoryDetailsForPool, isPoolFromRegisteredFactory, and isPoolOfType) are meant for offchain lookups. Each one calls IBasePoolFactory.isPoolFromFactory on every registered factory, active or deprecated, and skips any factory that reverts. Their gas cost therefore grows with the number of registered factories.
To check a pool onchain, your contract must already have the address of the factory that should have deployed it. For example, the caller can pass it in, or you can look it up by alias with getPoolFactory. Then run two checks:
- Ask the registry whether that address is an approved factory.
- Ask the factory whether it deployed the pool.
import { IBasePoolFactory } from "@bush.fi/v3-interfaces/contracts/vault/IBasePoolFactory.sol";
function validatePool(address pool, address factory) external view {
// 1. The factory must be registered. Pools from deprecated factories are still official
// pools, so check isRegistered. Use isActivePoolFactory(factory) instead only if the
// factory must also be the current one.
IBushContractRegistry.FactoryInfo memory info = registry.getPoolFactoryInfo(factory);
require(info.isRegistered, "Factory not registered");
// 2. The factory must have deployed this pool
require(IBasePoolFactory(factory).isPoolFromFactory(pool), "Pool not from factory");
// info.poolType, info.hookMode, info.hook are now available
}
If you only need to know that the factory is registered and active for a given pool type, use isActivePoolFactoryOfType(poolType, factory) as the first check instead.
When you don't know the factory, look it up offchain with getFactoryForPool(pool) (see Query the registry offchain), then pass that address into your onchain call.
Discover active factories for a pool type
address[] memory weightedFactories = registry.getPoolFactoriesByType("WEIGHTED", true); // activeOnly = true
A frontend or router can use this to offer pool creation only through the current recommended factory for a pool type, and to ignore deprecated factories.
Lookup by Alias
Find contracts using human-readable aliases:
(address factoryAddress, IBushContractRegistry.FactoryInfo memory info) = registry.getPoolFactory("WeightedPool");
require(info.isActive, "Factory not active");
// Use factoryAddress to create pool...
The generic getBushContract(ContractType.POOL_FACTORY, "WeightedPool") also works. It returns only the address and the active flag.
Query the registry offchain
Resources:
getAllPoolFactoryDetails() returns the same snapshot, plus each factory's live version and pool count. It makes several extra external calls per factory. Use it only if you need factoryVersion, poolVersion, isDisabled, or poolCount up front.
Events
| Event | Emitted when |
|---|---|
BushContractRegistered(contractType, contractName, contractAddress) | Any contract is registered, including pool factories. |
PoolFactoryRegistered(factory, name, poolType, hookMode, hook) | A pool factory is registered. It is emitted alongside BushContractRegistered. Its strings are not indexed, so you can read them from the event data. |
BushContractDeregistered(contractType, contractName, contractAddress) | Any contract is deregistered. contractType is indexed, so you can filter for POOL_FACTORY. |
BushContractDeprecated(contractAddress) | Any contract is deprecated. |
ContractAliasUpdated(contractAlias, contractAddress) | An alias is added or pointed at a new contract. |
Integration Guide
For Frontend Developers
- List available pool types with
getAllPoolFactories(). To find the current recommended factory for one pool type, usegetPoolFactoriesByType(poolType, true). - Display user-friendly names using aliases.
- Validate router addresses before transactions.
- When a user enters a pool address, resolve it with
getFactoryForPoolbefore showing it as an official Bush pool.
For Smart Contract Developers
When integrating with Bush:
- Always validate routers with
isTrustedRouter(). - Validate a pool before relying on standard Bush pool behavior. Starting from its expected factory, check that the factory is registered (
getPoolFactoryInfoorisRegisteredPoolFactory), then callIBasePoolFactory(factory).isPoolFromFactory(pool). Don't callgetFactoryForPoolor the other pool queries onchain, because they loop over every registered factory. - Pools from a deprecated factory are still valid. Skip only pools whose factory is deregistered (
isRegistered == false). - Don't assume a pool has no hook. Read
hookModeandhookfrom the registry. For anOPTIONALfactory, check the actual hook withIVault.getHooksConfig. - Consider caching active contracts to reduce gas.
For Aggregators and Indexers
- At startup, query the trusted routers. Call
getAllPoolFactories()to load the full set of known factories. UsegetAllPoolFactoryDetails()instead if you also need live version and pool-count data. - To keep the set current, listen for
PoolFactoryRegistered,BushContractDeregistered, andBushContractDeprecated.BushContractDeprecatedis emitted for every contract type. Match its address against your factory and router sets, or check it withgetBushContractInfo. - As you index the
PoolCreatedevents emitted by the factories, classify each pool with its factory'spoolTypeandhookModefromFactoryInfo. You don't need a hosted API. - Update your routing logic when routers or factories become inactive. Keep routing through existing pools from deprecated factories.
See Also
- Bush Contract Registry ABI
- Deployment Addresses
- Error Codes
- Vault Architecture
- Router Documentation
- Bush Deployments
- Solidity interface:
@bush.fi/v3-interfaces/contracts/standalone-utils/IBushContractRegistry.sol