Discovering Pools
POE supports an unbounded number of pools. Integrators do not have to hard-code each market: the Factory keeps a registry, so you can enumerate pools or look them up by pair on-chain.
The Factory address is the same on every supported chain (see POE Contracts):
Factory: 0x78120F2C0EBF0cc8B7E7749e62D36e6523dD711DFactory Lookup API
interface IFactory {
// Total number of pools ever created.
function getPoolsLength() external view returns (uint256);
// Index-based access. `poolId` is in [0, getPoolsLength()).
function getPoolAt(uint256 poolId) external view returns (address);
// Look up a pool by token pair. Returns address(0) if no pool exists.
function getPool(address tokenX, address tokenY) external view returns (address);
event PoolCreated(
uint256 indexed poolId,
address indexed pool,
address tokenX,
address tokenY,
bytes data
);
}getPool sorts the two token addresses internally. getPool(tokenX, tokenY) and getPool(tokenY, tokenX) return the same pool.
Do not use getPool lookup order to infer token roles. The pool's canonical ordering still comes from pool.getTokens(), and that ordering matters for oracle keys, swap direction, and amount interpretation.
Listing every pool
Enumerate [0, getPoolsLength()) and resolve each pool to its token pair:
The pool exposes the pair via getTokens() (returns the same (tokenX, tokenY) tuple the pool was initialized with) and its current balances via getBalances(). See Tracking Liquidity for the full pool read API.
TypeScript
Python
Looking up a specific pair
If you already know the pair, skip enumeration:
If getPool(a, b) returns address(0), getPool(b, a) will return the same result. A zero result means no pool exists for that token pair.
Reacting to new pools
Pool creation emits a PoolCreated event from the Factory. Indexers and integrators can subscribe to this to discover new markets without polling:
poolId is the index used by getPoolAt; data is the per-pool initialization blob (currently maxValue (12 bytes) | oracle (20 bytes)).
Last updated