Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GHO Stability Module Launch #169

Merged
merged 29 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
24a3f7d
Add proposal for Gho Incident Report 20231113 (#1)
parth-15 Dec 5, 2023
4aa6143
fix: Make new impl constant (#3)
miguelmtzinf Dec 6, 2023
27dd485
fix: Amend AIP text (#4)
miguelmtzinf Dec 6, 2023
2f242a6
test: Tweak default tests with borrow cap update (#5)
miguelmtzinf Dec 7, 2023
4812d01
fix: lint issue (#6)
parth-15 Dec 7, 2023
43a7687
test: Add diffs from test running (#7)
miguelmtzinf Dec 7, 2023
4c79bb9
fix: Add payload address (#8)
miguelmtzinf Dec 7, 2023
76cd4b6
fix: Fix payload address in script (#9)
miguelmtzinf Dec 7, 2023
120f564
fix: Remove unneeded diff file (#10)
miguelmtzinf Dec 7, 2023
4d6a3d9
Merge branch 'bgd-labs:main' into main
miguelmtzinf Dec 13, 2023
4cb8573
Merge branch 'bgd-labs:main' into main
miguelmtzinf Jan 16, 2024
7b657ec
feat: Add payload
miguelmtzinf Jan 17, 2024
30656b9
test: Add tests
miguelmtzinf Jan 18, 2024
6200cf4
feat: Add script and tests with final addresses
miguelmtzinf Jan 19, 2024
87121b9
fix: Fix link and gasLimit amounts
miguelmtzinf Jan 19, 2024
fd6aa81
fix: Update dependencies
miguelmtzinf Jan 19, 2024
698dc29
fix: Fix oracle swap freezer addresses
miguelmtzinf Jan 19, 2024
9d1c452
Merge branch 'bgd/main' into feat/gsm-launch
miguelmtzinf Jan 19, 2024
dab9aa1
fix: Bump block number for tests
miguelmtzinf Jan 19, 2024
e1c7f56
fix: Reduce LINK amount so its enough in treasury
miguelmtzinf Jan 19, 2024
f3ccff9
add test for OracleSwapFreezer
parth-15 Jan 19, 2024
8ce41b3
fix: Clean up in tests
miguelmtzinf Jan 19, 2024
0ffb368
docs: Add AIP text
miguelmtzinf Jan 19, 2024
168d0c8
docs: Fix typo in natspec docs
miguelmtzinf Jan 23, 2024
74f037f
fix: Fix typo on natspec docs
miguelmtzinf Jan 23, 2024
da11f18
docs: Fix typo in natspec docs
miguelmtzinf Jan 24, 2024
ecf22dc
fix: Add DAO as swap freezer
miguelmtzinf Jan 24, 2024
b5521d3
Merge branch 'main' of https://github.com/bgd-labs/aave-proposals-v3 …
miguelmtzinf Jan 24, 2024
2458f31
Merge branch 'main' into feat/gsm-launch
miguelmtzinf Jan 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/aave-helpers
Submodule aave-helpers updated 30 files
+1 −0 .assets/005b16eaa54199269ae451836387895a28c5d76e.svg
+1 −0 .assets/08d9252b4f8f8c9e59638a9a35a34e736f126166.svg
+0 −1 .assets/3bff92d2cfac98105fbeed24302d9d3577cb1325.svg
+1 −0 .assets/463b4c710a9b305cac1e136801dfbb5d2264a078.svg
+1 −0 .assets/5f02ea67e5ba53eee2797379ac1cd619db8b194e.svg
+0 −1 .assets/66aa72f6fe3716b9b6a43abb25a455671672849e.svg
+0 −1 .assets/6f34858c4ab5446d26b260c353dc36aa73d94358.svg
+1 −0 .assets/8062d95ddc9e1bec6e4a6b53fca46e335385d902.svg
+0 −1 .assets/9ed0ac5bda0d6aea5b627325dd757aab5a706122.svg
+1 −0 .assets/a9946a5d9adc46c59f833ceafb1d7a117d8d5e26.svg
+1 −0 .assets/cf503516adca0ef2b3e859f702e54d27d132edf2.svg
+0 −1 .assets/d89ecf5f1ccbeb07b104da02d99f5a5862da4efa.svg
+1 −0 .assets/ee0b6581b78f686087dd5f50440a7a76f4dd607d.svg
+1 −0 .assets/f75716c7eaa3c871931fca294b19538f6ade058c.svg
+4 −4 diffs/preTestEngineOptV3_postTestEngineOptV3.md
+4 −4 diffs/preTestEngineRates_postTestEngineRates.md
+1 −1 lib/forge-std
+176 −96 reports/default_after.json
+1,308 −1 reports/default_before.json
+79 −79 reports/postTestEngineOptV3.json
+76 −76 reports/postTestEngineRates.json
+76 −76 reports/preTestEngineOptV3.json
+76 −76 reports/preTestEngineRates.json
+1,508 −1 reports/preTestV2RatesUpdates.json
+0 −82 tests/GovTest.t.sol
+0 −71 tests/GovV2_5.t.sol
+2 −2 tests/GovV3Test.t.sol
+6 −5 tests/swaps/DepositV3SwapPayloadTest.t.sol
+1 −1 tests/v3-config-engine/AaveV3ConfigEngineTest.t.sol
+2 −2 tests/v3-config-engine/V3RateStrategyFactory.t.sol
73 changes: 73 additions & 0 deletions src/20240119_Gho_GHOStabilityModule/GHOStabilityModule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: "GHO Stability Module"
author: "Aave Labs @aave"
discussions: "https://governance.aave.com/t/gho-stability-module-update/14442"
---

## Simple Summary

This AIP proposes the deployment of the GHO Stability Module (GSM), a system facilitating the conversion between GHO and two governance-accepted stablecoins, USDC and USDT, at a predetermined ratio.

The GSM has undergone thorough iterations of design, development, testing, and implementation with Aave Labs driving this process and actively seeking community feedback. Additionally, the security aspect was carefully addressed through collaboration with DAO service providers SigmaPrime and Certora for code reviews. Furthermore, an extra layer of security was added by commissioning an independent review from a security researcher (Emanuele Ricci [@stermi](https://governance.aave.com/u/stermi/summary)).

Following extensive community discussion and multiple phases of Aave DAO governance, this AIP suggests deploying two GSM contracts for seamless conversions between GHO and USDC as well as GHO and USDT.

## Motivation

The GHO Stability Module (GSM) is a contract designed to facilitate conversions between two tokens with its primary purpose being to help further maintain GHO's peg. The module allows swaps between GHO and other governance-accepted stablecoins, offering a variety of functionalities that make it paramount in the fields of security and risk management.

Summarizing the functionality offered by the GHO Stability Module (GSM), here is a list of these features and their planned implementation for this proposal:

- **Exposure Cap**: Denominated in token units, it limits exposure to the exogenous asset.
- **Price Strategies**: Utilizing a fixed price strategy with a 1:1 ratio for stablecoins.
- **Fee Strategies**: Employing a flat basis point (bps) approach, differentiated by direction (sell/buy).
- **Last Resort Liquidation**: Aave DAO is the exclusive entity granted with the role of last resort liquidation, empowering it to take control of GSM funds in worst-case scenarios.
- **Swap Freeze**: Aave DAO and a chainlink-automated keeper contract have the authority to freeze the swap functionality. The chainlink-automated keeper contract bases its actions on the price of the exogenous asset, freezing if the price is outside the range and unfreezing if inside the range.
- **Capital Allocation**: Supporting this feature by allowing ERC4626 assets as underlying assets. This enables redirecting the yield generated by the ERC4626 asset, while residing in the GSM contract, to the GHO Treasury.

## Specification

The proposed payload entails the comprehensive activation of GSM USDC and GSM USDT, involving the following steps:

1. Incorporate GSM USDC and GSM USDT as facilitators of the GHO Token on Ethereum.
2. Adjust the Fee Strategy for both GSMs to implement a 2% flat fee for both directions (buy/sell).
miguelmtzinf marked this conversation as resolved.
Show resolved Hide resolved
3. Add both GSMs to the GSM Registry.
4. Designate OracleSwapFreezer contracts as SwapFreezer entities in each GSM contract, respectively.
5. Activate these OracleSwapFreezer contracts as keepers of the Aave DAO through AaveRobot with a funding of 80 LINK for each.

The table below outlines the initially proposed risk parameters for each GSM contract, as approved through the snapshot:

**GSM USDC**
| Parameter | Value |
|------------------------------------------ |----------------- |
| Underlying Price Range for Swap Freeze | [0.99 - 1.01] |
| Underlying Price Range for Swap Unfreeze | [0.995 - 1.005] |
| Buy Fee | 0.2% |
| Sell Fee | 0.2% |
| Exposure Cap | 500,000 USDC |
| Facilitator Bucket Capacity | 500,000 GHO |
| Swap Active | True |

**GSM USDT**
| Parameter | Value |
|------------------------------------------ |----------------- |
| Underlying Price Range for Swap Freeze | [0.99 - 1.01] |
| Underlying Price Range for Swap Unfreeze | [0.995 - 1.005] |
| Buy Fee | 0.2% |
| Sell Fee | 0.2% |
| Exposure Cap | 500,000 USDT |
| Facilitator Bucket Capacity | 500,000 GHO |
| Swap Active | True |

## References

- Implementation: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/20240119_Gho_GHOStabilityModule/AaveV3Ethereum_GHOStabilityModule_20240119.sol)
- Tests: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/20240119_Gho_GHOStabilityModule/AaveV3Ethereum_GHOStabilityModule_20240119.t.sol)
- [Snapshot](https://snapshot.org/#/aave.eth/proposal/0xe9b62e197a98832da7d1231442b5960588747f184415fba4699b6325d7618842)
- [Discussion](https://governance.aave.com/t/gho-stability-module-update/14442)
- [GSM Repository](https://github.com/aave/gho-core/tree/main/src/contracts/facilitators/gsm)
- [GSM Audit Reports](https://github.com/aave/gho-core/tree/main/audits)

## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {GovV3Helpers, IPayloadsControllerCore, PayloadsControllerUtils} from 'aave-helpers/GovV3Helpers.sol';
import {EthereumScript} from 'aave-helpers/ScriptUtils.sol';
import {Gho_GHOStabilityModule_20240119} from './Gho_GHOStabilityModule_20240119.sol';

/**
* @dev Deploy Ethereum
* deploy-command: make deploy-ledger contract=src/20240119_Gho_GHOStabilityModule/GHOStabilityModule_20240119.s.sol:DeployEthereum chain=mainnet
* verify-command: npx catapulta-verify -b broadcast/GHOStabilityModule_20240119.s.sol/1/run-latest.json
*/
contract DeployEthereum is EthereumScript {
function run() external broadcast {
// deploy payloads
address payload0 = GovV3Helpers.deployDeterministic(
type(Gho_GHOStabilityModule_20240119).creationCode
);

// compose action
IPayloadsControllerCore.ExecutionAction[]
memory actions = new IPayloadsControllerCore.ExecutionAction[](1);
actions[0] = GovV3Helpers.buildAction(payload0);

// register action at payloadsController
GovV3Helpers.createPayload(actions);
}
}

/**
* @dev Create Proposal
* command: make deploy-ledger contract=src/20240119_Gho_GHOStabilityModule/GHOStabilityModule_20240119.s.sol:CreateProposal chain=mainnet
*/
contract CreateProposal is EthereumScript {
function run() external {
// create payloads
PayloadsControllerUtils.Payload[] memory payloads = new PayloadsControllerUtils.Payload[](1);

// compose actions for validation
IPayloadsControllerCore.ExecutionAction[]
memory actionsEthereum = new IPayloadsControllerCore.ExecutionAction[](1);
actionsEthereum[0] = GovV3Helpers.buildAction(
type(Gho_GHOStabilityModule_20240119).creationCode
);
payloads[0] = GovV3Helpers.buildMainnetPayload(vm, actionsEthereum);

// create proposal
vm.startBroadcast();
GovV3Helpers.createProposal(
vm,
payloads,
GovV3Helpers.ipfsHashFile(vm, 'src/20240119_Gho_GHOStabilityModule/GHOStabilityModule.md')
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IProposalGenericExecutor} from 'aave-helpers/interfaces/IProposalGenericExecutor.sol';
import {AaveV3Ethereum, AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol';
import {MiscEthereum} from 'aave-address-book/MiscEthereum.sol';
import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol';
import {SafeERC20} from 'solidity-utils/contracts/oz-common/SafeERC20.sol';

interface IGhoToken {
function addFacilitator(
address facilitatorAddress,
string calldata facilitatorLabel,
uint128 bucketCapacity
) external;
}

interface IGsm {
function updateFeeStrategy(address feeStrategy) external;

function SWAP_FREEZER_ROLE() external pure returns (bytes32);

function grantRole(bytes32 role, address account) external;
}

interface IGsmRegistry {
function addGsm(address gsmAddress) external;
}

interface IAaveCLRobotOperator {
function register(
string memory name,
address upkeepContract,
uint32 gasLimit,
uint96 amountToFund
) external returns (uint256);
}

/**
* @title GHO Stability Module
* @author Aave labs (@aave)
* @dev This proposal enables 2 GHO Stability Modules (USDC, USDT):
* - Addition of USDC and USDT GSMs as GHO Facilitators
* - Give Swap Freezer permissions to OracleSwapFreezers, one per module
* - Install a 2% fee strategy into both modules
miguelmtzinf marked this conversation as resolved.
Show resolved Hide resolved
* - Register both GSMs in the GsmRegistry
* - Activate OracleSwapFreezer contracts as AaveRobot Keepers
* Relevant governance links:
* 1. GHO Stability Module
* - Snapshot: https://snapshot.org/#/aave.eth/proposal/0x98bdd30f645b2981320f82c671ae9fee31ee771766c13cd2627b66a22f0d438e
* - Discussion: https://governance.aave.com/t/temp-check-gho-stability-module/13927
* 2. GHO Stability Module Update
* - Discussion: https://governance.aave.com/t/gho-stability-module-update/14442
* 3. GHO Stability Module Launch
* - Snapshot: https://snapshot.org/#/aave.eth/proposal/0xe9b62e197a98832da7d1231442b5960588747f184415fba4699b6325d7618842
*/
contract Gho_GHOStabilityModule_20240119 is IProposalGenericExecutor {
using SafeERC20 for IERC20;

address public constant GSM_USDC = 0x0d8eFfC11dF3F229AA1EA0509BC9DFa632A13578;
address public constant GSM_USDC_ORACLE_SWAP_FREEZER = 0xef6beCa8D9543eC007bceA835aF768B58F730C1f;
address public constant GSM_USDT = 0x686F8D21520f4ecEc7ba577be08354F4d1EB8262;
address public constant GSM_USDT_ORACLE_SWAP_FREEZER = 0x71381e6718b37C12155CB961Ca3D374A8BfFa0e5;
address public constant GSM_REGISTRY = 0x167527DB01325408696326e3580cd8e55D99Dc1A;
address public constant GSM_FIXED_FEE_STRATEGY = 0xD4478A76aCeA81D3768A0ACB6e38f25eEB6Eb1B5;

string public constant GSM_USDC_FACILITATOR_LABEL = 'GSM USDC';
uint128 public constant GSM_USDC_BUCKET_CAPACITY = 500_000e18;
string public constant GSM_USDT_FACILITATOR_LABEL = 'GSM USDT';
uint128 public constant GSM_USDT_BUCKET_CAPACITY = 500_000e18;

address public constant ROBOT_OPERATOR = 0x020E452b463568f55BAc6Dc5aFC8F0B62Ea5f0f3;
uint96 public constant LINK_AMOUNT_ORACLE_FREEZER_KEEPER = 80 ether;
uint96 public constant TOTAL_LINK_AMOUNT_KEEPERS = LINK_AMOUNT_ORACLE_FREEZER_KEEPER * 2; // 2 GSMs
uint32 public constant KEEPER_GAS_LIMIT = 150_000;

function execute() external {
// 1. Enroll GSMs as GHO Facilitators
IGhoToken(MiscEthereum.GHO_TOKEN).addFacilitator(
GSM_USDC,
GSM_USDC_FACILITATOR_LABEL,
GSM_USDC_BUCKET_CAPACITY
);
IGhoToken(MiscEthereum.GHO_TOKEN).addFacilitator(
GSM_USDT,
GSM_USDT_FACILITATOR_LABEL,
GSM_USDT_BUCKET_CAPACITY
);

// 2. Add GSM Swap Freezer role to OracleSwapFreezers
IGsm(GSM_USDC).grantRole(IGsm(GSM_USDC).SWAP_FREEZER_ROLE(), GSM_USDC_ORACLE_SWAP_FREEZER);
IGsm(GSM_USDT).grantRole(IGsm(GSM_USDT).SWAP_FREEZER_ROLE(), GSM_USDT_ORACLE_SWAP_FREEZER);

// 3. Update Fee Strategy
IGsm(GSM_USDC).updateFeeStrategy(GSM_FIXED_FEE_STRATEGY);
IGsm(GSM_USDT).updateFeeStrategy(GSM_FIXED_FEE_STRATEGY);

// 4. Add GSMs to GSM Registry
IGsmRegistry(GSM_REGISTRY).addGsm(GSM_USDC);
IGsmRegistry(GSM_REGISTRY).addGsm(GSM_USDT);

// 5. Register OracleSwapFreezer as keepers
AaveV3Ethereum.COLLECTOR.transfer(
AaveV3EthereumAssets.LINK_UNDERLYING,
address(this),
TOTAL_LINK_AMOUNT_KEEPERS
);
IERC20(AaveV3EthereumAssets.LINK_UNDERLYING).forceApprove(
ROBOT_OPERATOR,
TOTAL_LINK_AMOUNT_KEEPERS
);

IAaveCLRobotOperator(ROBOT_OPERATOR).register(
'GHO GSM USDC OracleSwapFreezer',
GSM_USDC_ORACLE_SWAP_FREEZER,
KEEPER_GAS_LIMIT,
LINK_AMOUNT_ORACLE_FREEZER_KEEPER
brotherlymite marked this conversation as resolved.
Show resolved Hide resolved
);
IAaveCLRobotOperator(ROBOT_OPERATOR).register(
'GHO GSM USDT OracleSwapFreezer',
GSM_USDT_ORACLE_SWAP_FREEZER,
KEEPER_GAS_LIMIT,
LINK_AMOUNT_ORACLE_FREEZER_KEEPER
);
}
}
Loading