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

feat: gho stewards activation #276

Merged
merged 8 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Raw diff

```json
{}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IProposalGenericExecutor} from 'aave-helpers/interfaces/IProposalGenericExecutor.sol';
import {IGhoStewardV2} from './interfaces/IGhoStewardV2.sol';
import {IGhoToken} from './interfaces/IGho.sol';
import {IGsm} from './interfaces/IGsm.sol';
import {AaveV3Ethereum} from 'aave-address-book/AaveV3Ethereum.sol';
import {MiscEthereum} from 'aave-address-book/MiscEthereum.sol';

/**
* @title Activate Gho Stewards
* @author Aave Chan Initiative
* - Snapshot: https://snapshot.org/#/aave.eth/proposal/0x29f63b24638ee822f88632572ca4b061774771c0cc6d0ae5ccdeb538177232cd
* - Discussion: https://governance.aave.com/t/arfc-gho-stewards-borrow-rate-update/16956
*/
contract AaveV3Ethereum_ActivateGhoStewards_20240326 is IProposalGenericExecutor {
address public constant GHO_STEWARD = 0x8F2411a538381aae2b464499005F0211e867d84f;

function execute() external {
// Give pool admin role to the steward
AaveV3Ethereum.ACL_MANAGER.addPoolAdmin(GHO_STEWARD);

// Give bucket manager role to the steward
IGhoToken(MiscEthereum.GHO_TOKEN).grantRole(
IGhoToken(MiscEthereum.GHO_TOKEN).BUCKET_MANAGER_ROLE(),
GHO_STEWARD
);

// Give configurator role on usdc, usdt gsm to the stewards
IGsm(MiscEthereum.GSM_USDC).grantRole(
IGsm(MiscEthereum.GSM_USDC).CONFIGURATOR_ROLE(),
GHO_STEWARD
);
IGsm(MiscEthereum.GSM_USDT).grantRole(
IGsm(MiscEthereum.GSM_USDT).CONFIGURATOR_ROLE(),
GHO_STEWARD
);

// Whitelist all the facilitators on the stewards, including: GhoAToken, GhoFlashMinter, GSM USDC, GSM USDT
IGhoStewardV2(GHO_STEWARD).setControlledFacilitator(
IGhoToken(MiscEthereum.GHO_TOKEN).getFacilitatorsList(),
true
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IGhoStewardV2} from './interfaces/IGhoStewardV2.sol';
import {IGhoToken} from './interfaces/IGho.sol';
import {IGsmFeeStrategy} from './interfaces/IGsmFeeStrategy.sol';
import {IGsm} from './interfaces/IGsm.sol';
import {IDefaultInterestRateStrategy} from 'aave-v3-core/contracts/interfaces/IDefaultInterestRateStrategy.sol';
import {AaveV3Ethereum} from 'aave-address-book/AaveV3Ethereum.sol';
import {MiscEthereum} from 'aave-address-book/MiscEthereum.sol';
import {ProtocolV3TestBase} from 'aave-helpers/ProtocolV3TestBase.sol';
import {AaveV3Ethereum_ActivateGhoStewards_20240326} from './AaveV3Ethereum_ActivateGhoStewards_20240326.sol';

/**
* @dev Test for AaveV3Ethereum_ActivateGhoStewards_20240326
* command: make test-contract filter=AaveV3Ethereum_ActivateGhoStewards_20240326
*/
contract AaveV3Ethereum_ActivateGhoStewards_20240326_Test is ProtocolV3TestBase {
AaveV3Ethereum_ActivateGhoStewards_20240326 internal proposal;
address public RISK_COUNCIL;

function setUp() public {
vm.createSelectFork(vm.rpcUrl('mainnet'), 19519644);
proposal = new AaveV3Ethereum_ActivateGhoStewards_20240326();
RISK_COUNCIL = IGhoStewardV2(proposal.GHO_STEWARD()).RISK_COUNCIL();
}

/**
* @dev executes the generic test suite including e2e and config snapshots
*/
function test_defaultProposalExecution() public {
defaultTest(
'AaveV3Ethereum_ActivateGhoStewards_20240326',
AaveV3Ethereum.POOL,
address(proposal)
);
}

function test_adminPermissions() public {
executePayload(vm, address(proposal));

assertTrue(AaveV3Ethereum.ACL_MANAGER.isPoolAdmin(proposal.GHO_STEWARD()));
assertTrue(
IGhoToken(MiscEthereum.GHO_TOKEN).hasRole(
IGhoToken(MiscEthereum.GHO_TOKEN).BUCKET_MANAGER_ROLE(),
proposal.GHO_STEWARD()
)
);
assertTrue(
IGsm(MiscEthereum.GSM_USDT).hasRole(
IGsm(MiscEthereum.GSM_USDT).CONFIGURATOR_ROLE(),
proposal.GHO_STEWARD()
)
);
assertTrue(
IGsm(MiscEthereum.GSM_USDC).hasRole(
IGsm(MiscEthereum.GSM_USDC).CONFIGURATOR_ROLE(),
proposal.GHO_STEWARD()
)
);

address[] memory controlledFacilitatorsList = IGhoStewardV2(proposal.GHO_STEWARD())
.getControlledFacilitators();
address[] memory ghoFacilitatorList = IGhoToken(MiscEthereum.GHO_TOKEN).getFacilitatorsList();
assertEq(controlledFacilitatorsList.length, ghoFacilitatorList.length);

for (uint256 i = 0; i < controlledFacilitatorsList.length; i++) {
assertEq(controlledFacilitatorsList[i], ghoFacilitatorList[i]);
}
}

function testUpdateGhoBorrowRate() public {
executePayload(vm, address(proposal));

uint256 oldBorrowRate = _getGhoBorrowRate();
uint256 newBorrowRate = oldBorrowRate + 1;

vm.startPrank(RISK_COUNCIL);
IGhoStewardV2(proposal.GHO_STEWARD()).updateGhoBorrowRate(newBorrowRate);
vm.stopPrank();

uint256 currentBorrowRate = _getGhoBorrowRate();
assertEq(currentBorrowRate, newBorrowRate);
}

function testUpdateGhoBorrowCap() public {
executePayload(vm, address(proposal));

(uint256 oldBorrowCap, ) = AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER.getReserveCaps(
MiscEthereum.GHO_TOKEN
);
uint256 newBorrowCap = oldBorrowCap + 1;

vm.startPrank(RISK_COUNCIL);
IGhoStewardV2(proposal.GHO_STEWARD()).updateGhoBorrowCap(newBorrowCap);
vm.stopPrank();

(uint256 updatedBorrowCap, ) = AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER.getReserveCaps(
MiscEthereum.GHO_TOKEN
);
assertEq(newBorrowCap, updatedBorrowCap);
}

function testUpdateFacilitatorBucketCapacity() public {
executePayload(vm, address(proposal));
address[] memory ghoFacilitatorList = IGhoToken(MiscEthereum.GHO_TOKEN).getFacilitatorsList();

for (uint256 i = 0; i < ghoFacilitatorList.length; i++) {
address ghoFacilitator = ghoFacilitatorList[i];
(uint256 currentBucketCapacity, ) = IGhoToken(MiscEthereum.GHO_TOKEN).getFacilitatorBucket(
ghoFacilitator
);
uint128 newBucketCapacity = uint128(currentBucketCapacity) + 1;

vm.startPrank(RISK_COUNCIL);
IGhoStewardV2(proposal.GHO_STEWARD()).updateFacilitatorBucketCapacity(
ghoFacilitator,
newBucketCapacity
);
vm.stopPrank();

(uint256 updatedCapacity, ) = IGhoToken(MiscEthereum.GHO_TOKEN).getFacilitatorBucket(
ghoFacilitator
);
assertEq(newBucketCapacity, updatedCapacity);
}
}

function testUpdateGsmExposureCap() public {
executePayload(vm, address(proposal));

address[2] memory gsmList;
gsmList[0] = MiscEthereum.GSM_USDC;
gsmList[1] = MiscEthereum.GSM_USDT;

for (uint256 i = 0; i < gsmList.length; i++) {
address gsm = gsmList[i];

uint128 oldExposureCap = IGsm(gsm).getExposureCap();
uint128 newExposureCap = oldExposureCap + 1;

vm.startPrank(RISK_COUNCIL);
IGhoStewardV2(proposal.GHO_STEWARD()).updateGsmExposureCap(gsm, newExposureCap);
vm.stopPrank();

uint128 currentExposureCap = IGsm(gsm).getExposureCap();
assertEq(currentExposureCap, newExposureCap);
}
}

function testUpdateGsmBuySellFeesBuyFee() public {
executePayload(vm, address(proposal));

address[2] memory gsmList;
gsmList[0] = MiscEthereum.GSM_USDC;
gsmList[1] = MiscEthereum.GSM_USDT;

for (uint256 i = 0; i < gsmList.length; i++) {
address gsm = gsmList[i];

address feeStrategy = IGsm(gsm).getFeeStrategy();
uint256 buyFee = IGsmFeeStrategy(feeStrategy).getBuyFee(1e4);
uint256 sellFee = IGsmFeeStrategy(feeStrategy).getSellFee(1e4);

vm.startPrank(RISK_COUNCIL);
IGhoStewardV2(proposal.GHO_STEWARD()).updateGsmBuySellFees(gsm, buyFee + 1, sellFee + 1);
vm.stopPrank();

address newStrategy = IGsm(gsm).getFeeStrategy();
uint256 newBuyFee = IGsmFeeStrategy(newStrategy).getBuyFee(1e4);
uint256 newSellFee = IGsmFeeStrategy(newStrategy).getSellFee(1e4);

assertEq(newBuyFee, buyFee + 1);
assertEq(newSellFee, sellFee + 1);
}
}

function _getGhoBorrowRate() internal view returns (uint256) {
address currentInterestRateStrategy = AaveV3Ethereum
.AAVE_PROTOCOL_DATA_PROVIDER
.getInterestRateStrategyAddress(address(MiscEthereum.GHO_TOKEN));
return IDefaultInterestRateStrategy(currentInterestRateStrategy).getBaseVariableBorrowRate();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
title: "Activate Gho Stewards"
author: "Aave Chan Initiative"
discussions: "https://governance.aave.com/t/arfc-gho-stewards-borrow-rate-update/16956"
snapshot: "https://snapshot.org/#/aave.eth/proposal/0x29f63b24638ee822f88632572ca4b061774771c0cc6d0ae5ccdeb538177232cd"
---

## Simple Summary

brotherlymite marked this conversation as resolved.
Show resolved Hide resolved
This proposal activates GHO steward V2 for the Aave DAO, allowing better management of the GHO stablecoin by Risk, Growth & Finance Aave DAO service providers

## Motivation

brotherlymite marked this conversation as resolved.
Show resolved Hide resolved
This publication proposes to creating the GHO Stewards and granting the GHO Stewards permission to adjust the following parameters:

- GHO Borrow Cap
- GHO Borrow Rate
- GSM Exposure Cap
- GSM Bucket Capacity
- GSM Fee Strategy

GHO Stewards consists of members from Growth (ACI), Risk (ChaosLabs) and Finance (TokenLogic + Karpatkey) Service Providers and utilize a 3 of 4 multi-sig.

## Specification

brotherlymite marked this conversation as resolved.
Show resolved Hide resolved
The proposal gives the following admin roles:

- Grant GHO Steward the Pool Admin role via the [ACL_MANAGER](https://etherscan.io/address/0xc2aaCf6553D20d1e9d78E365AAba8032af9c85b0) contract.
- Grant GHO Steward the Bucket Manager role on the [GHO token](https://etherscan.io/address/0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f).
- Grant GHO Steward the Configurator role on [GSM_USDC](https://etherscan.io/address/0x0d8eFfC11dF3F229AA1EA0509BC9DFa632A13578) and [GSM_USDT](https://etherscan.io/address/0x686F8D21520f4ecEc7ba577be08354F4d1EB8262).
- Whitelists all the facilitators on the GHO Stewards, including: [GHO_AToken](https://etherscan.io/address/0x00907f9921424583e7ffBfEdf84F92B7B2Be4977), [GHO_FlashMinter](https://etherscan.io/address/0xb639D208Bcf0589D54FaC24E655C79EC529762B8), [GSM_USDC](https://etherscan.io/address/0x0d8eFfC11dF3F229AA1EA0509BC9DFa632A13578), [GSM_USDT](https://etherscan.io/address/0x686F8D21520f4ecEc7ba577be08354F4d1EB8262) - so that the steward has the permissions to update the bucket capacity.

The GHO Stewards parameters are set as follow:

- GHO Aave Bucket Capacity: 100% increase
- GHO Borrow Rate: 5% change
- GSM Exposure Cap: 100% increase
- GSM Bucket Capacity: 100% increase
- GHO Borrow Cap: 100% increase
- GSM Fee Strategy: +0.5%

## References

- GHO Steward SAFE address: [0x8513e6F37dBc52De87b166980Fa3F50639694B60](https://etherscan.io/address/0x8513e6F37dBc52De87b166980Fa3F50639694B60)
- GHO Steward V2 address: [0x8F2411a538381aae2b464499005F0211e867d84f](https://etherscan.io/address/0x8F2411a538381aae2b464499005F0211e867d84f)
- GHO Steward Repo: [GhoStewardV2.sol](https://github.com/aave/gho-core/blob/f02f87482de7ccbd30ba76b40939fb016dbb2fea/src/contracts/misc/GhoStewardV2.sol)
- Implementation: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/20240326_AaveV3Ethereum_ActivateGhoStewards/AaveV3Ethereum_ActivateGhoStewards_20240326.sol)
- Tests: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/20240326_AaveV3Ethereum_ActivateGhoStewards/AaveV3Ethereum_ActivateGhoStewards_20240326.t.sol)
- [Snapshot](https://snapshot.org/#/aave.eth/proposal/0x29f63b24638ee822f88632572ca4b061774771c0cc6d0ae5ccdeb538177232cd)
- [Discussion](https://governance.aave.com/t/arfc-gho-stewards-borrow-rate-update/16956)

## 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,58 @@
// 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 {AaveV3Ethereum_ActivateGhoStewards_20240326} from './AaveV3Ethereum_ActivateGhoStewards_20240326.sol';

/**
* @dev Deploy Ethereum
* deploy-command: make deploy-ledger contract=src/20240326_AaveV3Ethereum_ActivateGhoStewards/ActivateGhoStewards_20240326.s.sol:DeployEthereum chain=mainnet
* verify-command: npx catapulta-verify -b broadcast/ActivateGhoStewards_20240326.s.sol/1/run-latest.json
*/
contract DeployEthereum is EthereumScript {
function run() external broadcast {
// deploy payloads
address payload0 = GovV3Helpers.deployDeterministic(
type(AaveV3Ethereum_ActivateGhoStewards_20240326).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/20240326_AaveV3Ethereum_ActivateGhoStewards/ActivateGhoStewards_20240326.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(AaveV3Ethereum_ActivateGhoStewards_20240326).creationCode
);
payloads[0] = GovV3Helpers.buildMainnetPayload(vm, actionsEthereum);

// create proposal
vm.startBroadcast();
GovV3Helpers.createProposal(
vm,
payloads,
GovV3Helpers.ipfsHashFile(
vm,
'src/20240326_AaveV3Ethereum_ActivateGhoStewards/ActivateGhoStewards.md'
)
);
}
}
14 changes: 14 additions & 0 deletions src/20240326_AaveV3Ethereum_ActivateGhoStewards/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {ConfigFile} from '../../generator/types';
export const config: ConfigFile = {
rootOptions: {
pools: ['AaveV3Ethereum'],
title: 'Activate Gho Stewards',
shortName: 'ActivateGhoStewards',
date: '20240326',
author: 'Aave Chan Initiative',
discussion: 'https://governance.aave.com/t/arfc-gho-stewards-borrow-rate-update/16956',
snapshot:
'https://snapshot.org/#/aave.eth/proposal/0x29f63b24638ee822f88632572ca4b061774771c0cc6d0ae5ccdeb538177232cd',
},
poolOptions: {AaveV3Ethereum: {configs: {OTHERS: {}}, cache: {blockNumber: 19519644}}},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IAccessControl} from 'aave-v3-core/contracts/dependencies/openzeppelin/contracts/IAccessControl.sol';

interface IGhoToken is IAccessControl {
function BUCKET_MANAGER_ROLE() external pure returns (bytes32);

function getFacilitatorsList() external view returns (address[] memory);

function getFacilitatorBucket(address facilitator) external view returns (uint256, uint256);
}
Loading
Loading