diff --git a/docs/concepts/core-concepts/architecture.md b/docs/concepts/core-concepts/architecture.md index 5e5e2d37..572bf90e 100644 --- a/docs/concepts/core-concepts/architecture.md +++ b/docs/concepts/core-concepts/architecture.md @@ -5,7 +5,7 @@ order: 1 # Architecture -## Core Components +## Core components The Balancer protocol architecture comprises three primary components, each strategically designed to enhance flexibility and minimize the intricacies involved in constructing pools. By distributing responsibilities across these components, Balancer simplifies pool development, empowering builders to focus on innovation rather than grappling with complex code. @@ -15,42 +15,51 @@ The Balancer protocol architecture comprises three primary components, each stra This design philosophy ensures that building pools on Balancer is intuitive and efficient, with the vault shouldering the burden of complexity, allowing pool creators to unleash their creativity without worrying about accounting details. -## Transaction Flow +## Simplified transaction flow The following diagram illustrates the usage of each component during a transaction. -![Router Vault interaction](/images/architecture-1.png) +![Router Vault interaction](/images/architecture-simplified.png) 1. The [Router](/concepts/router/technical.html) acts as the primary interface for accessing the Balancer protocol, offering a user-friendly way to interact with the Balancer Vault. -2. The Router establishes a TAB with the [Vault](/concepts/vault), which records all credits and debts generated by operations like adding liquidity, removing liquidity, and swaps. +2. The Router unlocks the [Vault](/concepts/vault), which allows it to continue by recording all credits and debts generated by operations like adding liquidity, removing liquidity, and swaps. -3. In the case of a swap, the pool's invariant, which is defined in the pool contract, determines the quantity of tokens being either deposited (`EXACT_OUT` swap) in the Vault or withdrawn (`EXACT_IN` swap) from the Vault. +3. The Vault processes the operations instructed by the Router, usually forwarding requests to pools. For example, in the case of a swap, the pool's invariant, which is defined in the pool contract, determines the quantity of tokens being either deposited (`EXACT_OUT` swap) in the Vault or withdrawn (`EXACT_IN` swap) from the Vault. +Once the required token amounts have been calculated, these amounts are recorded as either credit or debt in the Vault. -4. Once the required token amounts have been calculated, these amounts are recorded as either credit or debt in the Vault. +4. The Vault returns back the operation results to the Router. -5. To maintain accurate accounting and ensure the Vault's token balances align with its internal accounting, the Router's accrued credit and/or debt must be settled by the end of the transaction. - -6. In the final step, the Vault verifies that the Router has correctly settled its accrued debts and credits. The transaction will only succeed if everything has been accurately settled; otherwise, it will revert. +5. The Router settles debts and credits by sending tokens to the Vault to pay debts, and pulling tokens out of the Vault to clear out credits. +The Vault verifies that the Router has correctly settled its accrued debts and credits properly. The transaction will only succeed if every single debit and credit has been accurately settled; otherwise, it will be reverted. ## Detailed overview -![Detailed Router Vault interaction](/images/architecture-2.png) +![Detailed Router Vault interaction](/images/architecture-detailed.png) 1. The Balancer Router is the main interface for interacting with Balancer, providing a user-friendly way to access functions and simplify interactions with the Vault. Any smart contract can serve as a Router, tailored to the specific use case. 2. The Router calls the Vault's `unlock` method and opens up the vault to record debts & credits based on liquidity or swap operations. This allows operations on the Vault to be combined atomically and still ensure correct accounting. -3. With the Vault unlocked, the Vault calls back into the Router. For example, in the case of a swap action, the Vault calls the Router's specific action hook implementation, such as `swapSingleTokenHook`, and passes the initial function payload from step 1 back to the Router to continue the regular transaction flow. +3. With the Vault unlocked, the Vault calls back into the Router. This is where arbitrary logic can be executed, including any combination of calls to Vault primitives, interacting with external protocols, etc. +For example, in the case of a swap action, the Vault calls the Router's specific action hook implementation, such as `swapSingleTokenHook`, and passes the initial function payload from step 1 back to the Router to continue the regular transaction flow. + +4. At this stage, any address gains authorization to invoke the Vault's functions that require the Vault to be unlocked identifier by the `onlyWhenUnlocked` modifier. This mechanism guarantees the accurate allocation of debt and credit: the Vault will track how many tokens of each kind are owed to it (debt), and how many tokens can be pulled out of it (credit). +The inputs from step 1 are passed to the Vault's core functions, such as swap. -4. Once the Router has unlocked the Vault, any address may invoke Vault functions that require the Vault to be unlocked (i.e., those with the `onlyWhenUnlocked` modifier). This mechanism guarantees the accurate allocation of debt and credit. +5. Each primitive operation performed on the Vault might trigger function calls on pools to calculate the result of the operation: +- `onSwap` for swaps +- `calculateInvariant` or `computeBalance` for liquidity management operations (add / remove), depending on the operation kind. +These functions calculate the tokens that need to be deposited into or withdrawn from the Vault. +Proportional liquidity management operations are an exception to this rule: the math is solved at the Vault level in this case. -5. Each primitive operation performed on the Vault triggers the execution of either the `computeInvariant` or `computeBalance` function, defined by the pool. These functions calculate the tokens that need to be deposited into or withdrawn from the Vault. The outcome of these calculations is allocated to either debt or credit, which must be settled at a later stage. Additionally, the required amount of Balancer Pool Tokens (BPT) is minted or burned accordingly. (Note that for security reasons, BPT tokens do not participate in transient accounting.) +6. The outcomes of these calculations are attributed as either debt or credit, which must be settled at a later stage. Additionally, the required amount of Balancer Pool Tokens (BPT) is minted or burned accordingly in the case of liquidity management operations. -6. Pools can be extended with standalone hook contracts that can be leveraged at different stages of the pool's lifecycle. These hook contracts can be called either before or after a pool operation, depending on how the pool is configured during deployment. Using hooks, developers can customize and enhance the functionality of pools, enabling the integration of features like oracles or time-weighted average market makers. +7. After debt & credit has been recorded for and shared with the Router by the Vault, the execution flow is passed to the Router. This allows the Router to be aware of the amounts owed (both by the sender to the Vault, and vice-versa). +It is important to mention that the Router contract has the ability to retrieve the current debt and credit owed to the Vault at any point during the execution by calling a specific function on the Vault. -7. After debts & credits have been recorded by the Vault, the execution flow is passed to the Router. This allows the Router to be aware of the amounts owed. It is important to mention that the Router contract has the ability to retrieve the current debt and credit owed to the Vault at any point during the execution by calling a specific function on the Vault. +8. The Router is responsible for settling the remaining debt and credit, which must be done for the transaction to succeed. If ETH or WETH is to be used in the transaction, the Router wraps or unwraps Ether right before settling WETH debts. -8. The Router is responsible for settling the remaining debt and credit, which must be done for the transaction to succeed. ETH can be deposited to or withdrawn from any pool containing WETH. If ETH is used in the transaction, the wrapping or unwrapping is done by the Router. (Note that the Vault itself never uses Ether; trying to send ETH to the Vault will revert.) +9. When the router is done with settlement, the Vault verifies that all credit and debt accrued during the operations has been settled as the final step. Once the verification is complete, the Vault is locked again. If all debt has been correctly settled, the transaction will succeed; otherwise, it will be reverted. -9. The final step involves verifying that all credit and debt accrued during the operations has been settled. Once the verification is complete, the Vault is locked again. If all debt has been correctly settled, the transaction will succeed; otherwise, it will revert. +On top of the basic workflow, pools can be extended with standalone hooks contracts that can be leveraged at different stages of the pool's lifecycle. These hooks contracts can be called either before or after a pool operation (i.e. step 5), depending on how the pool is configured during deployment. By utilizing hooks, developers can customize and enhance the functionality of pools, enabling the integration of features like oracles or time-weighted average market maker capabilities. See [hooks](./hooks.md) article for more detailed information about it. diff --git a/images/architecture-detailed.png b/images/architecture-detailed.png new file mode 100644 index 00000000..c04e1ae2 Binary files /dev/null and b/images/architecture-detailed.png differ diff --git a/images/architecture-simplified.png b/images/architecture-simplified.png new file mode 100644 index 00000000..660420dc Binary files /dev/null and b/images/architecture-simplified.png differ