One very powerful feature of Balancer is the concept of Smart Pools. A smart contract controlled pool can fully emulate a finalized pool, while also allowing complex logic to readjust balances, weights, and fees. Some examples include:
A pool that adjusts swap fees as a function of the volatility of the pool's assets
A pool that updates weights to implement a particular market strategy (e.g., a Liquidity Bootstrapping Pool).
More complex dynamic strategies for asset allocation
For clarity, here is a graphical representation of the process for creating both Core Pools and Smart Pools - it can be a little confusing keeping all the addresses straight!
In a nutshell, Balancer has deployed Factory contracts for creating pools. Users deploy new pool contracts by calling create methods on these factories. In both cases, the actual "pool" visible to traders on the public interfaces is a new BPool contract.
If you deploy a Core Pool directly, you are the controller of that pool. If you deploy a Smart Pool, you need to pass in the core BFactory address, since two contracts will be deployed. You are the controller of the Smart Pool - and the Smart Pool itself is the controller of the BPool.
There are three categories of things you can do with pools.
Trade - using the swap functions
Provide liquidity - using the join/exit pool functions (both single- and multi-asset entry and exit are supported)
Manage the pool - if you are the controller (e.g., change its parameters)
Core Pools can only be managed until "finalized," after which their parameters are immutable.
Smart Pools are managed according to the rights granted to the controller on creation. For instance, you can create a Smart Pool where the weights can be changed, but the swap fee and token composition are fixed.
Notice that e.g.
joinswap requires both