Skip to content

Commit

Permalink
StkGHO Initialization proposal (bgd-labs#170)
Browse files Browse the repository at this point in the history
* Add proposal for Gho Incident Report 20231113 (#1)

* chore: add payload and deploy script for update of GHO variable debt token

* forge install: gho-core

* chore: add gho-core to dependency

* test: Add tests for update of gho variable token

* test: Add tests for update of gho variable token

* fix: add modifier in method of interface

* fix: remove gho dependency from repo and fix test

* fix: Remove unnecesary dependency

* fix: Add latest details

---------

Co-authored-by: miguelmtzinf <miguelmtz.mail@gmail.com>

* fix: Make new impl constant (#3)

* fix: Amend AIP text (#4)

* fix: Make new impl constant

* fix: Fix AIP text

* test: Tweak default tests with borrow cap update (#5)

* fix: lint issue (#6)

* test: Add diffs from test running (#7)

* fix: Add payload address (#8)

* fix: Fix payload address in script (#9)

* fix: Remove unneeded diff file (#10)

* feat: added stkgho initialization proposal

* feat: fixed proposal description

* feat: removed submodule

* feat: fixed deployment script

* feat: replaced duration calculation

* git commit remove submodule

* feat: fixed payload build function

* update proposal

* sync branch

* fix: variable name

* fix: Fix AIP payload

* fix: Fix tests

* test: added further test on emission per day

* refactor: removed unused constants

* fix: catapulta commands

* fix: Add fixes to payload

* fix: Rebuild proposal with autogenerate tool

---------

Co-authored-by: Parth Patel <parth4321patel@gmail.com>
Co-authored-by: miguelmtzinf <miguelmtz.mail@gmail.com>
Co-authored-by: miguelmtz <36620902+miguelmtzinf@users.noreply.github.com>
Co-authored-by: Mark Hinschberger <foodaka@users.noreply.github.com>
  • Loading branch information
5 people authored Jan 20, 2024
1 parent 95d84cd commit 1982811
Show file tree
Hide file tree
Showing 10 changed files with 448 additions and 7 deletions.
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"vitest": "^1.0.4"
},
"dependencies": {
"@bgd-labs/aave-address-book": "^2.14.0",
"@bgd-labs/aave-address-book": "^2.17.0",
"@bgd-labs/aave-cli": "0.2.1",
"@inquirer/prompts": "^3.3.0",
"@inquirer/testing": "^2.1.9",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.0;

import 'forge-std/Test.sol';
import {AaveV3EthereumAssets, AaveV3Ethereum} from 'aave-address-book/AaveV3Ethereum.sol';
import {AaveV3Ethereum, AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol';
import {ProtocolV3TestBase} from 'aave-helpers/ProtocolV3TestBase.sol';
import {IPoolConfigurator} from 'aave-address-book/AaveV3.sol';
import {AaveV3Ethereum_GhoIncidentReport_20231113} from './AaveV3Ethereum_GhoIncidentReport_20231113.sol';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IProposalGenericExecutor} from 'aave-helpers/interfaces/IProposalGenericExecutor.sol';
import {MiscEthereum} from 'aave-address-book/MiscEthereum.sol';
import {AaveV3Ethereum, AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol';
import {AaveSafetyModule} from 'aave-address-book/AaveSafetyModule.sol';
import {IStakeToken} from './IStakeToken.sol';

/**
* @title StkGHO Activation
* @author Aave Labs & ACI
* - Snapshot: https://snapshot.org/#/aave.eth/proposal/0x4bc99a842adab6cdd8c7d5c7a787ee4c0056be554fde0d008d53b45b3e795065
* - Discussion: https://governance.aave.com/t/arfc-upgrade-safety-module-with-stkgho/15635
*/
contract AaveV3Ethereum_StkGHOActivation_20240119 is IProposalGenericExecutor {
uint128 public constant AAVE_EMISSION_PER_SECOND = uint128(50e18) / 1 days; // 50 AAVE per day
uint256 public constant DISTRIBUTION_DURATION = 90 days; // 3 months

function execute() external {
// Configure distribution
IStakeToken(AaveSafetyModule.STK_GHO).setDistributionEnd(
block.timestamp + DISTRIBUTION_DURATION
);
IStakeToken.AssetConfigInput[] memory enableConfigs = new IStakeToken.AssetConfigInput[](1);
enableConfigs[0] = IStakeToken.AssetConfigInput({
emissionPerSecond: AAVE_EMISSION_PER_SECOND,
totalStaked: 0, // it's overwritten internally
underlyingAsset: AaveSafetyModule.STK_GHO
});
IStakeToken(AaveSafetyModule.STK_GHO).configureAssets(enableConfigs);

// Allowance to pull funds from Ecosystem Reserve
MiscEthereum.AAVE_ECOSYSTEM_RESERVE_CONTROLLER.approve(
MiscEthereum.ECOSYSTEM_RESERVE,
AaveV3EthereumAssets.AAVE_UNDERLYING,
AaveSafetyModule.STK_GHO,
AAVE_EMISSION_PER_SECOND * DISTRIBUTION_DURATION
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {AaveV3Ethereum, AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol';

import 'forge-std/Test.sol';
import {ProtocolV3TestBase, ReserveConfig} from 'aave-helpers/ProtocolV3TestBase.sol';
import {MiscEthereum} from 'aave-address-book/MiscEthereum.sol';
import {AaveSafetyModule} from 'aave-address-book/AaveSafetyModule.sol';
import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol';
import {IStakeToken} from './IStakeToken.sol';
import {AaveV3Ethereum_StkGHOActivation_20240119} from './AaveV3Ethereum_StkGHOActivation_20240119.sol';

/**
* @dev Test for AaveV3Ethereum_StkGHOActivation_20240119
* command: make test-contract filter=AaveV3Ethereum_StkGHOActivation_20240119
*/
contract AaveV3Ethereum_StkGHOActivation_20240119_Test is ProtocolV3TestBase {
AaveV3Ethereum_StkGHOActivation_20240119 internal proposal;

function setUp() public {
vm.createSelectFork(vm.rpcUrl('mainnet'), 19042382);
proposal = new AaveV3Ethereum_StkGHOActivation_20240119();
}

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

function test_checkConfig() public {
(uint128 emissionPerSecondBefore, , ) = IStakeToken(AaveSafetyModule.STK_GHO).assets(
AaveV3EthereumAssets.GHO_UNDERLYING
);

executePayload(vm, address(proposal));

(
uint128 emissionPerSecondAfter,
uint128 lastUpdateTimestampAfter, // uint256 indexAfter

) = IStakeToken(AaveSafetyModule.STK_GHO).assets(AaveSafetyModule.STK_GHO);

// NOTE index is still 0
assertEq(emissionPerSecondBefore + emissionPerSecondAfter, proposal.AAVE_EMISSION_PER_SECOND());
assertEq(lastUpdateTimestampAfter, block.timestamp);
}

function test_checkAllowance() public {
uint256 allowanceBefore = IERC20(AaveV3EthereumAssets.AAVE_UNDERLYING).allowance(
MiscEthereum.ECOSYSTEM_RESERVE,
AaveSafetyModule.STK_GHO
);

executePayload(vm, address(proposal));

uint256 allowanceAfter = IERC20(AaveV3EthereumAssets.AAVE_UNDERLYING).allowance(
MiscEthereum.ECOSYSTEM_RESERVE,
AaveSafetyModule.STK_GHO
);

assertEq(
allowanceAfter - allowanceBefore,
proposal.AAVE_EMISSION_PER_SECOND() * proposal.DISTRIBUTION_DURATION()
);
}

function test_checkRewards() public {
address prankAddress = 0xF5Fb27b912D987B5b6e02A1B1BE0C1F0740E2c6f;

uint256 confidenceMargin = 1e6; // margin of error due to rounding
uint256 rewardsPerDay = 50e18;

executePayload(vm, address(proposal));

// impersonating address with AAVE balance
vm.startPrank(prankAddress);
IERC20(AaveV3EthereumAssets.GHO_UNDERLYING).approve(AaveSafetyModule.STK_GHO, 1e18);

IStakeToken(AaveSafetyModule.STK_GHO).stake(prankAddress, 1e18);

vm.warp(block.timestamp + 1 days);

uint256 rewardsBalance = IStakeToken(AaveSafetyModule.STK_GHO).getTotalRewardsBalance(
prankAddress
);

assertTrue(
rewardsBalance >= (rewardsPerDay - confidenceMargin) &&
rewardsBalance <= (rewardsPerDay + confidenceMargin)
);

vm.stopPrank();
}
}
194 changes: 194 additions & 0 deletions src/20240119_AaveV3Ethereum_StkGHOActivation/IStakeToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
pragma solidity ^0.8.10;

interface IStakeToken {
event Approval(address indexed owner, address indexed spender, uint256 value);
event AssetConfigUpdated(address indexed asset, uint256 emission);
event AssetIndexUpdated(address indexed asset, uint256 index);
event Cooldown(address indexed user, uint256 amount);
event CooldownSecondsChanged(uint256 cooldownSeconds);
event DistributionEndChanged(uint256 endTimestamp);
event EIP712DomainChanged();
event ExchangeRateChanged(uint216 exchangeRate);
event FundsReturned(uint256 amount);
event Initialized(uint64 version);
event MaxSlashablePercentageChanged(uint256 newPercentage);
event PendingAdminChanged(address indexed newPendingAdmin, uint256 role);
event Redeem(address indexed from, address indexed to, uint256 assets, uint256 shares);
event RewardsAccrued(address user, uint256 amount);
event RewardsClaimed(address indexed from, address indexed to, uint256 amount);
event RoleClaimed(address indexed newAdmin, uint256 role);
event Slashed(address indexed destination, uint256 amount);
event SlashingExitWindowDurationChanged(uint256 windowSeconds);
event SlashingSettled();
event Staked(address indexed from, address indexed to, uint256 assets, uint256 shares);
event Transfer(address indexed from, address indexed to, uint256 value);
event UserIndexUpdated(address indexed user, address indexed asset, uint256 index);

struct AssetConfigInput {
uint128 emissionPerSecond;
uint256 totalStaked;
address underlyingAsset;
}

function CLAIM_HELPER_ROLE() external view returns (uint256);

function COOLDOWN_ADMIN_ROLE() external view returns (uint256);

function DOMAIN_SEPARATOR() external view returns (bytes32);

function EMISSION_MANAGER() external view returns (address);

function EXCHANGE_RATE_UNIT() external view returns (uint256);

function INITIAL_EXCHANGE_RATE() external view returns (uint216);

function LOWER_BOUND() external view returns (uint256);

function PRECISION() external view returns (uint8);

function REWARDS_VAULT() external view returns (address);

function REWARD_TOKEN() external view returns (address);

function SLASH_ADMIN_ROLE() external view returns (uint256);

function STAKED_TOKEN() external view returns (address);

function UNSTAKE_WINDOW() external view returns (uint256);

function allowance(address owner, address spender) external view returns (uint256);

function approve(address spender, uint256 value) external returns (bool);

function assets(
address
) external view returns (uint128 emissionPerSecond, uint128 lastUpdateTimestamp, uint256 index);

function balanceOf(address account) external view returns (uint256);

function claimRewards(address to, uint256 amount) external;

function claimRewardsAndRedeem(address to, uint256 claimAmount, uint256 redeemAmount) external;

function claimRewardsAndRedeemOnBehalf(
address from,
address to,
uint256 claimAmount,
uint256 redeemAmount
) external;

function claimRewardsOnBehalf(
address from,
address to,
uint256 amount
) external returns (uint256);

function claimRoleAdmin(uint256 role) external;

function configureAssets(AssetConfigInput[] memory assetsConfigInput) external;

function cooldown() external;

function cooldownOnBehalfOf(address from) external;

function decimals() external view returns (uint8);

function distributionEnd() external view returns (uint256);

function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);

function getAdmin(uint256 role) external view returns (address);

function getCooldownSeconds() external view returns (uint256);

function getExchangeRate() external view returns (uint216);

function getMaxSlashablePercentage() external view returns (uint256);

function getPendingAdmin(uint256 role) external view returns (address);

function getTotalRewardsBalance(address staker) external view returns (uint256);

function getUserAssetData(address user, address asset) external view returns (uint256);

function inPostSlashingPeriod() external view returns (bool);

function initialize(
string memory name,
string memory symbol,
address slashingAdmin,
address cooldownPauseAdmin,
address claimHelper,
uint256 maxSlashablePercentage,
uint256 cooldownSeconds
) external;

function name() external view returns (string memory);

function nonces(address owner) external view returns (uint256);

function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;

function previewRedeem(uint256 shares) external view returns (uint256);

function previewStake(uint256 assets) external view returns (uint256);

function redeem(address to, uint256 amount) external;

function redeemOnBehalf(address from, address to, uint256 amount) external;

function returnFunds(uint256 amount) external;

function setCooldownSeconds(uint256 cooldownSeconds) external;

function setDistributionEnd(uint256 newDistributionEnd) external;

function setMaxSlashablePercentage(uint256 percentage) external;

function setPendingAdmin(uint256 role, address newPendingAdmin) external;

function settleSlashing() external;

function slash(address destination, uint256 amount) external returns (uint256);

function stake(address to, uint256 amount) external;

function stakeWithPermit(
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;

function stakerRewardsToClaim(address) external view returns (uint256);

function stakersCooldowns(address) external view returns (uint40 timestamp, uint216 amount);

function symbol() external view returns (string memory);

function totalSupply() external view returns (uint256);

function transfer(address to, uint256 value) external returns (bool);

function transferFrom(address from, address to, uint256 value) external returns (bool);
}
37 changes: 37 additions & 0 deletions src/20240119_AaveV3Ethereum_StkGHOActivation/StkGHOActivation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
title: "StkGHO Activation"
author: "Aave Labs & ACI"
discussions: "https://governance.aave.com/t/arfc-upgrade-safety-module-with-stkgho/15635"
---

## Simple Summary

This AIP activates the new GHO based Safety module by initiating the emission schedule approved by the community during the [Snapshot vote](https://snapshot.org/#/aave.eth/proposal/0x4bc99a842adab6cdd8c7d5c7a787ee4c0056be554fde0d008d53b45b3e795065)

## Motivation

The GHO Safety Module will fortify the Aave Protocol’s resilience by adding a stablecoin asset, which is inherently less volatile than AAVE. This strategic move diversifies the Safety Module’s capacity to absorb shocks from various risk vectors in case of shortfall events.

## Specification

The GHO Safety module will be activated with the following parameters:

- Base emission: 50 AAVE/day
- Duration: Three months

## References

- Implementation: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/20240119_AaveV3Ethereum_StkGHOActivation/AaveV3Ethereum_StkGHOActivation_20240119.sol)
- Tests: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/main/src/20240119_AaveV3Ethereum_StkGHOActivation/AaveV3Ethereum_StkGHOActivation_20240119.t.sol)
- [Snapshot](https://snapshot.org/#/aave.eth/proposal/0x4bc99a842adab6cdd8c7d5c7a787ee4c0056be554fde0d008d53b45b3e795065)
- [Discussion](https://governance.aave.com/t/arfc-upgrade-safety-module-with-stkgho/15635)
- [StkGHO](https://etherscan.io/address/0x1a88Df1cFe15Af22B3c4c783D4e6F7F9e0C1885d)
- [StakeToken Repository](https://github.com/bgd-labs/stake-token)

## Disclaimer

Aave Labs, and ACI receive no compensation beyond Aave protocol for the creation of this proposal. ACI is delegate within the Aave ecosystem.

## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
Loading

0 comments on commit 1982811

Please sign in to comment.