This repository was archived by the owner on Nov 1, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 29
Aave V3 Ethereum: Handle Strategic Assets #208
Open
efecarranza
wants to merge
28
commits into
bgd-labs:main
Choose a base branch
from
llamaxyz:assets
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 23 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
5f18360
feat: strategic assets
efecarranza a530d0e
chore; start test
efecarranza 361e4a6
feat: add tests SD tokens
efecarranza ab4ae69
feat: add vote gauge weight test
efecarranza c4a9662
Merge remote-tracking branch 'origin/main' into assets
efecarranza 675e5b6
feat: add lsd tests
efecarranza b4b5461
chore: remove unused functions
efecarranza 7bfb8e0
feat: add missing locking tests
efecarranza 2da6f22
chore: updates of solidity version
efecarranza d5c4655
feat: use Ownable.sol and Initializable.sol
efecarranza 2f4bfbe
feat: initialize with ownership
efecarranza 4a1cb29
feat: include README with function signatures
efecarranza 367e493
Merge remote-tracking branch 'origin/main' into assets
efecarranza 52cfba1
feat: switch to using ownable with guardian
efecarranza 8256d0c
chore use approve
efecarranza 9f6e90e
feat: simplify to handle only veBAL
efecarranza 3e5d590
chore: updates per PR review
efecarranza 32ef455
chore: add missing natspecs
efecarranza f5001ce
chore: add missing event and fix natspec
efecarranza 479e34a
Merge remote-tracking branch 'origin/main' into assets
efecarranza 45d878d
feat: add VLAURA support
efecarranza 136bed8
Merge remote-tracking branch 'origin/main' into assets
efecarranza b8c6a40
feat: add tests for vlaura
efecarranza 512866e
feat: update natspec
efecarranza bda519c
feat: update README to include vlAURA functions
efecarranza 2eaa696
chore: remove mention of sd token
efecarranza 3d58410
feat: update PR with natspec and revert
efecarranza a4acaa6
feat: update guardian address
efecarranza File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity 0.8.19; | ||
|
|
||
| import {OwnableWithGuardian} from 'solidity-utils/contracts/access-control/OwnableWithGuardian.sol'; | ||
|
|
||
| abstract contract Common is OwnableWithGuardian { | ||
| /// @notice Provided address is zero address | ||
| error InvalidZeroAddress(); | ||
|
|
||
| /// @notice One week, in seconds. Vote-locking is rounded down to weeks. | ||
| uint256 internal constant WEEK = 7 days; | ||
| } |
27 changes: 27 additions & 0 deletions
27
src/AaveV3StrategicAssets_20230606/DeployStrategicAssetsManager.s.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.0; | ||
|
|
||
| import {GovHelpers} from 'aave-helpers/GovHelpers.sol'; | ||
| import {EthereumScript} from 'aave-helpers/ScriptUtils.sol'; | ||
|
|
||
| import {StrategicAssetsManagerPayload} from './StrategicAssetsManagerPayload.sol'; | ||
|
|
||
| contract DeployAssetManagementContracts is EthereumScript { | ||
| function run() external broadcast { | ||
| new StrategicAssetsManagerPayload(); | ||
| } | ||
| } | ||
|
|
||
| contract DeployStrategicAssetsProposal is EthereumScript { | ||
| function run() external broadcast { | ||
| GovHelpers.Payload[] memory payloads = new GovHelpers.Payload[](1); | ||
| payloads[0] = GovHelpers.buildMainnet(address(0)); | ||
| GovHelpers.createProposal( | ||
| payloads, | ||
| GovHelpers.ipfsHashFile( | ||
| vm, | ||
| 'src/AaveV3StrategicAssets_20230606/AIP-STRATEGIC-ASSETS-MANAGER.md' | ||
| ) | ||
| ); | ||
| } | ||
| } | ||
40 changes: 40 additions & 0 deletions
40
src/AaveV3StrategicAssets_20230606/LSDLiquidityGaugeManager.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity 0.8.19; | ||
|
|
||
| import {ILiquidityGaugeController} from './interfaces/ILiquidityGaugeController.sol'; | ||
| import {Common} from './Common.sol'; | ||
|
|
||
| abstract contract LSDLiquidityGaugeManager is Common { | ||
| event GaugeControllerChanged(address indexed oldController, address indexed newController); | ||
| event GaugeVote(address indexed gauge, uint256 amount); | ||
|
|
||
| /// @notice Setting to the same controller address as currently set. | ||
| error SameController(); | ||
|
|
||
| /// @notice Address of LSD Gauge Controller | ||
| address public gaugeControllerBalancer; | ||
|
|
||
| /// @notice Set the gauge controller used for gauge weight voting | ||
| /// @param _gaugeController The gauge controller address | ||
| function setGaugeController(address _gaugeController) public onlyOwnerOrGuardian { | ||
| if (_gaugeController == address(0)) revert InvalidZeroAddress(); | ||
|
|
||
| address oldController = gaugeControllerBalancer; | ||
| if (oldController == _gaugeController) revert SameController(); | ||
|
|
||
| gaugeControllerBalancer = _gaugeController; | ||
|
|
||
| emit GaugeControllerChanged(oldController, gaugeControllerBalancer); | ||
| } | ||
|
|
||
| /// @notice Vote for a gauge's weight | ||
| /// @param gauge the address of the gauge to vote for | ||
| /// @param weight the weight of gaugeAddress in basis points [0, 10.000] | ||
| function voteForGaugeWeight(address gauge, uint256 weight) external onlyOwnerOrGuardian { | ||
| if (gauge == address(0)) revert InvalidZeroAddress(); | ||
|
|
||
| ILiquidityGaugeController(gaugeControllerBalancer).vote_for_gauge_weights(gauge, weight); | ||
| emit GaugeVote(gauge, weight); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| # Streategic Assets Manager Information | ||
|
|
||
| ## Main Idea | ||
brotherlymite marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| The main idea of this new contract is for the DAO to be able to handle strategic assets (assets that will earn rewards, or assets that can be used to | ||
| vote on different protocols, for example) without the need to go through the full governance flow every week. | ||
|
|
||
| Take the following example: the DAO wants to hold veBAL as part of its strategy for the long term. To get the most out of veBAL, the DAO should "re-lock" | ||
| its holdings on a weekly basis. This is a very tedious approach and can lead to a lot of voter fatigue. Because of this, the StrategicAssetsManager contract | ||
| can be governed by the DAO, while some functions can be invoked by an allowed guardian, acting on the role of Asset Manager. | ||
|
|
||
| ## Functionality | ||
|
|
||
| #### StrategicAssetsManager.sol | ||
|
|
||
| Removes the ability to interact with a certain sdToken. | ||
|
|
||
| `function withdrawERC20(address token, address to, uint256 amount) external onlyOwner` | ||
|
|
||
| Sends ERC20 tokens to an address. Withdrawal mechanism. | ||
|
|
||
| `function updateGuardian(address _manager) external onlyOwner` | ||
|
|
||
| Updates guardian role, which in this contract functions as a strategic asset manager. Inherited from OwnableWithGuardian. | ||
|
|
||
| `function transferOwnership(address _owner) external onlyOwner` | ||
|
|
||
| Updates the owner of the contract. Inherited from Ownable. | ||
|
|
||
| #### VeTokenManager.sol | ||
|
|
||
| ``` | ||
| function buyBoost( | ||
| address underlying, | ||
| address delegator, | ||
| address receiver, | ||
| uint256 amount, | ||
| uint256 duration | ||
| ) external onlyOwnerOrManager | ||
| ``` | ||
|
|
||
| Purchase boost to incentivize rewards earned by locking (up to 2.5x of earnings). Spend fee token. | ||
| For more info see: https://doc.paladin.vote/warden-boost/boost-market | ||
|
|
||
| The idea is to increase the yield in the provided liquidity. | ||
| For example, pay 10 BAL to boost rewards in a veBAL pool up to 2.5x times, to earn more BAL in return. | ||
|
|
||
| ``` | ||
| function sellBoost( | ||
| address underlying, | ||
| uint256 pricePerVote, | ||
| uint64 maxDuration, | ||
| uint64 expiryTime, | ||
| uint16 minPerc, | ||
| uint16 maxPerc, | ||
| bool useAdvicePrice | ||
| ) external onlyOwnerOrManager | ||
| ``` | ||
|
|
||
| Owner of veToken allows others to incentivize their liquidity pools by selling boost. The price can be chosen by the user, or by setting useAdvicePrice, let Warden determine the price. | ||
| The seller of boost receives the native token. | ||
|
|
||
| ``` | ||
| function updateBoostOffer( | ||
| address underlying, | ||
| uint256 pricePerVote, | ||
| uint64 maxDuration, | ||
| uint64 expiryTime, | ||
| uint16 minPerc, | ||
| uint16 maxPerc, | ||
| bool useAdvicePrice | ||
| ) external onlyOwnerOrManager | ||
| ``` | ||
|
|
||
| Allows the user to update an existing offer to sell boost. | ||
|
|
||
| `function removeBoostOffer(address underlying) external onlyOwnerOrManager` | ||
|
|
||
| Removes a boost offer. | ||
|
|
||
| ` function claim(address underlying) external onlyOwnerOrManager` | ||
|
|
||
| Claim rewards earned by selling boost. | ||
|
|
||
| `function setSpaceId(address underlying, bytes32 _spaceId) external onlyOwnerOrManager` | ||
|
|
||
| Sets the spaceID that's used by protocol on Snapshot for voting. For example, "balancer.eth" is Balancer's spaceId on Snapshot. | ||
|
|
||
| ``` | ||
| function setDelegate( | ||
| address underlying, | ||
| address newDelegate | ||
| ) external onlyOwnerOrManager | ||
| ``` | ||
|
|
||
| Delegate tokens so they can vote on Snapshot. | ||
|
|
||
| `function clearDelegate(address underlying) external onlyOwnerOrManager` | ||
|
|
||
| Remove the active delegate. | ||
|
|
||
| ``` | ||
| function setLockDuration( | ||
| address underlying, | ||
| uint256 newLockDuration | ||
| ) external onlyOwnerOrManager | ||
| ``` | ||
|
|
||
| Set the lock duration to specific time. For example, max lock for veBAL is 1 year, so set to 1 year (or less). | ||
|
|
||
| `function lock(address underlying) external onlyOwnerOrManager` | ||
|
|
||
| The main function for veBAL. | ||
| Initially, it locks the B-80BAL-20WETH token to receive veBAL. (This contract needs to be allow-listed by Balancer prior to calling or it will fail). | ||
| On subsequent calls (for example, weekly) it extends the lock duration once again. The voting % available per token is dependent on the locking duration. | ||
| If locking duration is 6 months and the maximum duration is 1 year, then the voting weight is only half. | ||
| This function also locks more of the native token held by StrategicAssetsManager available on the contract. | ||
|
|
||
| `function unlock(address underlying) external onlyOwnerOrManager` | ||
|
|
||
| Unlocks the veToken in order to receive the underlying once again. Lock duration needs to have passed or transaction will revert. | ||
|
|
||
| ##### LSDLiquidityGaugeManager.sol | ||
|
|
||
| `function setGaugeController(address token, address gaugeController) public onlyOwnerOrManager` | ||
|
|
||
| Sets the address that handles gauges for sdTokens or veTokens. | ||
|
|
||
| Here is the proposal on Balancer as it relates to GHO: https://forum.balancer.fi/t/bip-xxx-approve-the-smbpt-gauges-for-the-aave-sm/4949 | ||
| This post has the explanation on all the steps the DAO can expect to interact with these protocols to maximize rewards. | ||
| The excalidraw towards the bottom of the page is helpful in seeing the full flow. | ||
|
|
||
| Curve docs on liquidity gauges: https://curve.readthedocs.io/dao-gauges.html | ||
|
|
||
| The main concept here is that the ecosystem rewards liquidity providers by rewarding them with token emissions. These tokens are distributed according to which gauges receive the | ||
| most votes. | ||
|
|
||
| ``` | ||
| function voteForGaugeWeight( | ||
| address token, | ||
| address gauge, | ||
| uint256 weight | ||
| ) external onlyOwnerOrManager | ||
| ``` | ||
|
|
||
| Utilizing the veToken holdings or sdToken holdings, the DAO can vote to redirect emissions to the DAO's own gauge. | ||
| Here, by voting for the DAO's gauge, and also purchasing boost, the DAO can expect to earn a lot more BAL rewards over time than just by holding a veToken for example. | ||
37 changes: 37 additions & 0 deletions
37
src/AaveV3StrategicAssets_20230606/StrategicAssetsManager.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity 0.8.19; | ||
|
|
||
| import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol'; | ||
| import {Initializable} from 'solidity-utils/contracts/transparent-proxy/Initializable.sol'; | ||
| import {SafeERC20} from 'solidity-utils/contracts/oz-common/SafeERC20.sol'; | ||
| import {AaveGovernanceV2} from 'aave-address-book/AaveGovernanceV2.sol'; | ||
efecarranza marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| import {AaveV3Ethereum} from 'aave-address-book/AaveV3Ethereum.sol'; | ||
|
|
||
| import {LSDLiquidityGaugeManager} from './LSDLiquidityGaugeManager.sol'; | ||
| import {VeTokenManager} from './VeTokenManager.sol'; | ||
| import {VlTokenManager} from './VlTokenManager.sol'; | ||
|
|
||
| contract StrategicAssetsManager is | ||
brotherlymite marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Initializable, | ||
| LSDLiquidityGaugeManager, | ||
| VeTokenManager, | ||
| VlTokenManager | ||
| { | ||
| using SafeERC20 for IERC20; | ||
|
|
||
| event WithdrawalERC20(address indexed _token, uint256 _amount); | ||
|
|
||
| function initialize() external initializer { | ||
| _transferOwnership(AaveGovernanceV2.SHORT_EXECUTOR); | ||
| _updateGuardian(_msgSender()); | ||
|
||
| spaceIdBalancer = 'balancer.eth'; | ||
| gaugeControllerBalancer = 0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD; | ||
| lockDurationVEBAL = 365 days; | ||
| } | ||
|
|
||
| function withdrawERC20(address token, uint256 amount) external onlyOwner { | ||
| IERC20(token).safeTransfer(address(AaveV3Ethereum.COLLECTOR), amount); | ||
| emit WithdrawalERC20(token, amount); | ||
| } | ||
| } | ||
20 changes: 20 additions & 0 deletions
20
src/AaveV3StrategicAssets_20230606/StrategicAssetsManagerPayload.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| pragma solidity 0.8.19; | ||
|
|
||
| import {AaveMisc} from 'aave-address-book/AaveMisc.sol'; | ||
| import {IProposalGenericExecutor} from 'aave-helpers/interfaces/IProposalGenericExecutor.sol'; | ||
| import {TransparentProxyFactory} from 'solidity-utils/contracts/transparent-proxy/TransparentProxyFactory.sol'; | ||
|
|
||
| import {StrategicAssetsManager} from './StrategicAssetsManager.sol'; | ||
|
|
||
| contract StrategicAssetsManagerPayload is IProposalGenericExecutor { | ||
| function execute() external { | ||
| address strategicAssetsManager = address(new StrategicAssetsManager()); | ||
| TransparentProxyFactory(AaveMisc.TRANSPARENT_PROXY_FACTORY_ETHEREUM).create( | ||
| strategicAssetsManager, | ||
| AaveMisc.PROXY_ADMIN_ETHEREUM, | ||
| abi.encodeWithSelector(StrategicAssetsManager.initialize.selector) | ||
| ); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@efecarranza I think we don't need a proposal for this no, as we can just deploy and set the permission of the asset manager to the executor and guardian and that's it... or am I missing something.