From 121d5fef0b7df58d2406e10ac6a37d3d9e700dee Mon Sep 17 00:00:00 2001 From: fabianschu <48454910+fabianschu@users.noreply.github.com> Date: Wed, 24 Nov 2021 18:05:33 +0100 Subject: [PATCH 1/5] adds more info --- handover.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 handover.md diff --git a/handover.md b/handover.md new file mode 100644 index 0000000000..870098798a --- /dev/null +++ b/handover.md @@ -0,0 +1,67 @@ +# Handover + +## 1. Specification + +### 1.1. Rebalancing + +#### 1.1.1. General + +- [x] there is public function `reweighTokens` +- [x] it takes the following arguments: + - [x] IERC20[] calldata tokens + - [x] uint256[] calldata desiredWeights +- [x] input validation: + - [x] it reverts if input arrays are malformed +- [x] can only be called by controller + +#### 1.1.2. Cases + +- [x] base case: the fn parameters contain target weights for all pool tokens, in the pool there is no uninitialized token and no token to be removed atm + - [x] a new rebalancing process is initialized using the current weights as start weights and the target weights as end weights + - [x] the endTime is calculated such that the weight change per day for the token with the largest absolute weight change is 1% per day (consequently the weight change for the other tokens is smaller than that) +- [ ] case: the fn parameters contain target weights for all pool tokens, there is an uninitialized token in the pool + - [ ] only the target weights of the initialized tokens are changed, the uninitialized token stays at 1% + - [ ] the new target weight of the uninitialized token is stored for later use +- [ ] case: there is a token that is currently being removed from the pool, there is no target weight specified for this token by the fn params + - [ ] the target weights for the tokens from the params are set correctly (adjusted by the 1% target weight of the to-be-removed-token) + +### 1.2. Reindexing + +#### 1.2.1. General + +- [x] there is public function `reweighTokens` +- [x] input validation +- [x] can only be called by controller + +#### 1.2.2. Cases + +- [x] adding one token + - [x] if a token passed to `reindexTokens` does not yet exist in the process to add a token is initiated + - [x] it's weight is set to 1% as long as it is uninitialized (uninitialized = the token's pool balance is below the specified minimumBalance) + - [x] it can only be swapped into the pool, but not out + - [x] if the token is swapped the price is calculacted based on the 1% base weight and a fake pool balance of minimumBalance + - [ ] price premium mechanism + - [ ] the token's weight is increased by a premium depending on how far its pool balance is away from the minimumBalance + - [x] the util function to calculcate this "incentivized weight" has been built `IndexPoolUtils.getUninitializedTokenWeight` + - [x] initialization behavior: + - [x] if a swap pushes it's pool balance over the minimumBalance the token becomes initialized + - [x] its current weight is immediately adjusted relative to the amount that its pool balance exceeds the minimum balance + - [x] a new rebalancing is initiaited, this time taking into account the final target weight of the initialized token (as provided by the original reindex call) +- [x] adding multiple tokens at once +- [x] removing one token + - [x] if a pool token is not contained by the params of `reindexTokens` the process to remove that token is initiated + - [x] its target weight is set to 1% and it is flagged to be removed + - [x] it can only be swapped out of the pool but not in + - [x] if the token has reached 1% its residual amount can be sent to a token handler contract by calling `removeFinalizedTokens` which removes the token from the pool +- [x] removing multiple tokens at once +- [x] adding & removing tokens at once + +## 2. Documentation + +### 2.1. General V2 design + +Balancer V2's architecture builds on the premise that pool and vault are separate contracts. The vault holds all tokens, keeps a registry of available pools and their respective token balances. If a user makes a basic interaction with a pool such as swapping, joinning or exiting, this happens through an interaction with the vault (thereby the user specifies with which pool they want to interact). The vault will forward the interaction to the respective pool, whose implementation determines the exact swap, join, or exit logic (e.g. how much a user will receive for a given swap). This division between pool and vault has significant implications on the possible design space for the `IndexPool`. + +### 2.2. Starting point: InvestmentPool + +Balancer is currently working on a new smart pool implementation, the `InvestmentPool`. This pool is meant to cater for a large amount of tokens, to allow for reweighing and more. However, the InvestmentPool is work in progress. The InvestmentPool was used as starting point for the IndexPool implementation, since it shares many of its desired features. From 73027c7d5c18e5745cbb7bcb1d187b25c827ce06 Mon Sep 17 00:00:00 2001 From: Fabian Scherer <48454910+fabianschu@users.noreply.github.com> Date: Thu, 25 Nov 2021 14:32:39 +0100 Subject: [PATCH 2/5] Update handover.md --- handover.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/handover.md b/handover.md index 870098798a..5f2389b9f1 100644 --- a/handover.md +++ b/handover.md @@ -6,10 +6,10 @@ #### 1.1.1. General -- [x] there is public function `reweighTokens` -- [x] it takes the following arguments: - - [x] IERC20[] calldata tokens - - [x] uint256[] calldata desiredWeights +- [x] there is public function `reweighTokens` +- [x] it takes the following arguments: + - [x] IERC20[] calldata tokens + - [x] uint256[] calldata desiredWeights - [x] input validation: - [x] it reverts if input arrays are malformed - [x] can only be called by controller From 765d6303c882584045979b436205c2a8dfd457eb Mon Sep 17 00:00:00 2001 From: fabianschu <48454910+fabianschu@users.noreply.github.com> Date: Mon, 29 Nov 2021 11:34:29 +0100 Subject: [PATCH 3/5] more documentation --- handover.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/handover.md b/handover.md index 5f2389b9f1..7b7c2ef404 100644 --- a/handover.md +++ b/handover.md @@ -58,10 +58,14 @@ ## 2. Documentation -### 2.1. General V2 design +### 2.1. High level Balancer V2 architecture Balancer V2's architecture builds on the premise that pool and vault are separate contracts. The vault holds all tokens, keeps a registry of available pools and their respective token balances. If a user makes a basic interaction with a pool such as swapping, joinning or exiting, this happens through an interaction with the vault (thereby the user specifies with which pool they want to interact). The vault will forward the interaction to the respective pool, whose implementation determines the exact swap, join, or exit logic (e.g. how much a user will receive for a given swap). This division between pool and vault has significant implications on the possible design space for the `IndexPool`. ### 2.2. Starting point: InvestmentPool -Balancer is currently working on a new smart pool implementation, the `InvestmentPool`. This pool is meant to cater for a large amount of tokens, to allow for reweighing and more. However, the InvestmentPool is work in progress. The InvestmentPool was used as starting point for the IndexPool implementation, since it shares many of its desired features. +Balancer is currently working on a new smart pool implementation, the `InvestmentPool`. This pool is meant to cater for a large amount of tokens, to allow for reweighing and more. However, the InvestmentPool is work in progress. The already existing code for the InvestmentPool was used as starting point for the IndexPool implementation, since it shares many of its desired features. + +### 2.3. Storage + +In the current implementation the pool stores token specific information as a mapping `address => bytes32`. Within the `bytes32` most of the state of the respective token is stored. This includes the token's `startWeight`, `endWeight`, `decimals`. For an uninitialized (new) token this also includes its `targetWeight`, for a token to be removes its `TODO` From d99abc8aee3fb5f78537a3c5cc65bc4f1ec4220f Mon Sep 17 00:00:00 2001 From: fabianschu <48454910+fabianschu@users.noreply.github.com> Date: Mon, 29 Nov 2021 11:38:56 +0100 Subject: [PATCH 4/5] more documentation --- handover.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/handover.md b/handover.md index 7b7c2ef404..2bd0a0c4e4 100644 --- a/handover.md +++ b/handover.md @@ -6,19 +6,19 @@ #### 1.1.1. General -- [x] there is public function `reweighTokens` -- [x] it takes the following arguments: - - [x] IERC20[] calldata tokens - - [x] uint256[] calldata desiredWeights +- [x] there is public function `reweighTokens` +- [x] it takes the following arguments: + - [x] IERC20[] calldata tokens + - [x] uint256[] calldata desiredWeights - [x] input validation: - [x] it reverts if input arrays are malformed - [x] can only be called by controller #### 1.1.2. Cases -- [x] base case: the fn parameters contain target weights for all pool tokens, in the pool there is no uninitialized token and no token to be removed atm - - [x] a new rebalancing process is initialized using the current weights as start weights and the target weights as end weights - - [x] the endTime is calculated such that the weight change per day for the token with the largest absolute weight change is 1% per day (consequently the weight change for the other tokens is smaller than that) +- [x] base case: the fn parameters contain target weights for all pool tokens, in the pool there is no uninitialized token and no token to be removed atm + - [x] a new rebalancing process is initialized using the current weights as start weights and the target weights as end weights + - [x] the endTime is calculated such that the weight change per day for the token with the largest absolute weight change is 1% per day (consequently the weight change for the other tokens is smaller than that) - [ ] case: the fn parameters contain target weights for all pool tokens, there is an uninitialized token in the pool - [ ] only the target weights of the initialized tokens are changed, the uninitialized token stays at 1% - [ ] the new target weight of the uninitialized token is stored for later use @@ -68,4 +68,8 @@ Balancer is currently working on a new smart pool implementation, the `Investmen ### 2.3. Storage -In the current implementation the pool stores token specific information as a mapping `address => bytes32`. Within the `bytes32` most of the state of the respective token is stored. This includes the token's `startWeight`, `endWeight`, `decimals`. For an uninitialized (new) token this also includes its `targetWeight`, for a token to be removes its `TODO` +In the current implementation the pool stores token specific information as a mapping `address => bytes32`. Within the `bytes32` most of the state of the respective token is stored. This includes the token's `startWeight`, `endWeight`, `decimals`. For an uninitialized (new) token this also includes its `targetWeight`, for a token to be removes its `TODO`. What is not currently stored within this tokenState is the token's `minimumBalance`. For this data, there exists a separate mapping. A desirable **optimization** would definitely to include the `minimumBalance` within the more general token state to save on gas costs. + +### 2.4. Contract Size + +The base contract that the `IndexPool` inherits from, `BaseWeightedPool`, is already relatively large in size. Due to the way params will be passed from the controller to the reweighing and reindexing functions, the `IndexPool`'s core logic requires relatively many loops/arrays. To save on contract size, we loaded off much of this computation into a library with external function visibility, `IndexPoolUtils`. For the yet outstanding implementations, it will likely be necessary to follow this approach. In this context it might be worth to have another look if the way functions are split between the pool and the libraray can be optimized. The tradeoffs here are that offloading a function into the library reduces the pool's contract size, but on the other hand makes each call to this funciton more expensive. So ideally, one would like to have the functions that are complex (hence, large in code size) and that are called not so frequently to live in the library, whereas "small" functions that are called frequently should rather reside in the pool implementation itself. From 6047c47ab929950dd0e86bf893ce166db9e90469 Mon Sep 17 00:00:00 2001 From: fabianschu <48454910+fabianschu@users.noreply.github.com> Date: Mon, 29 Nov 2021 11:43:09 +0100 Subject: [PATCH 5/5] formatting issues --- handover.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/handover.md b/handover.md index 2bd0a0c4e4..315baa7585 100644 --- a/handover.md +++ b/handover.md @@ -6,19 +6,19 @@ #### 1.1.1. General -- [x] there is public function `reweighTokens` -- [x] it takes the following arguments: - - [x] IERC20[] calldata tokens - - [x] uint256[] calldata desiredWeights +- [x] there is public function `reweighTokens` +- [x] it takes the following arguments: + - [x] IERC20[] calldata tokens + - [x] uint256[] calldata desiredWeights - [x] input validation: - [x] it reverts if input arrays are malformed - [x] can only be called by controller #### 1.1.2. Cases -- [x] base case: the fn parameters contain target weights for all pool tokens, in the pool there is no uninitialized token and no token to be removed atm - - [x] a new rebalancing process is initialized using the current weights as start weights and the target weights as end weights - - [x] the endTime is calculated such that the weight change per day for the token with the largest absolute weight change is 1% per day (consequently the weight change for the other tokens is smaller than that) +- [x] base case: the fn parameters contain target weights for all pool tokens, in the pool there is no uninitialized token and no token to be removed atm + - [x] a new rebalancing process is initialized using the current weights as start weights and the target weights as end weights + - [x] the endTime is calculated such that the weight change per day for the token with the largest absolute weight change is 1% per day (consequently the weight change for the other tokens is smaller than that) - [ ] case: the fn parameters contain target weights for all pool tokens, there is an uninitialized token in the pool - [ ] only the target weights of the initialized tokens are changed, the uninitialized token stays at 1% - [ ] the new target weight of the uninitialized token is stored for later use @@ -29,7 +29,7 @@ #### 1.2.1. General -- [x] there is public function `reweighTokens` +- [x] there is public function `reweighTokens` - [x] input validation - [x] can only be called by controller