diff --git a/.assets/a2ff7054b21a6d938826bbea32b5e589c6a0c8f7.svg b/.assets/a2ff7054b21a6d938826bbea32b5e589c6a0c8f7.svg new file mode 100644 index 000000000..514bc6bd2 --- /dev/null +++ b/.assets/a2ff7054b21a6d938826bbea32b5e589c6a0c8f7.svg @@ -0,0 +1 @@ + Borrow APR, variableBorrow APR, stable0%25%50%75%100%0%50%100%uOptimal 80%uOptimal 80% \ No newline at end of file diff --git a/.assets/c73865a243e2110291617da971e6614d404cd2c5.svg b/.assets/c73865a243e2110291617da971e6614d404cd2c5.svg new file mode 100644 index 000000000..be739493a --- /dev/null +++ b/.assets/c73865a243e2110291617da971e6614d404cd2c5.svg @@ -0,0 +1 @@ + Borrow APR, variableBorrow APR, stable0%25%50%75%100%0%5%10%uOptimal 0%uOptimal 0% \ No newline at end of file diff --git a/diffs/AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528_before_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528_after.md b/diffs/AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528_before_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528_after.md new file mode 100644 index 000000000..3e3bd04bc --- /dev/null +++ b/diffs/AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528_before_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528_after.md @@ -0,0 +1,134 @@ +## Reserve changes + +### Reserves added + +#### USDe ([0x4c9EDD5852cd905f086C759E8383e09bff1E68B3](https://etherscan.io/address/0x4c9EDD5852cd905f086C759E8383e09bff1E68B3)) + +| description | value | +| --- | --- | +| decimals | 18 | +| isActive | true | +| isFrozen | false | +| supplyCap | 80,000,000 USDe | +| borrowCap | 72,000,000 USDe | +| debtCeiling | 40,000,000 $ | +| isSiloed | false | +| isFlashloanable | true | +| eModeCategory | 0 | +| oracle | [0x55B6C4D3E8A27b8A1F5a263321b602e0fdEEcC17](https://etherscan.io/address/0x55B6C4D3E8A27b8A1F5a263321b602e0fdEEcC17) | +| oracleDecimals | 8 | +| oracleDescription | Capped USDe / USD | +| oracleLatestAnswer | 1.00079999 | +| usageAsCollateralEnabled | true | +| ltv | 72 % | +| liquidationThreshold | 75 % | +| liquidationBonus | 8.5 % | +| liquidationProtocolFee | 10 % | +| reserveFactor | 25 % | +| aToken | [0x4F5923Fc5FD4a93352581b38B7cD26943012DECF](https://etherscan.io/address/0x4F5923Fc5FD4a93352581b38B7cD26943012DECF) | +| aTokenImpl | [0x7EfFD7b47Bfd17e52fB7559d3f924201b9DbfF3d](https://etherscan.io/address/0x7EfFD7b47Bfd17e52fB7559d3f924201b9DbfF3d) | +| variableDebtToken | [0x015396E1F286289aE23a762088E863b3ec465145](https://etherscan.io/address/0x015396E1F286289aE23a762088E863b3ec465145) | +| variableDebtTokenImpl | [0xaC725CB59D16C81061BDeA61041a8A5e73DA9EC6](https://etherscan.io/address/0xaC725CB59D16C81061BDeA61041a8A5e73DA9EC6) | +| stableDebtToken | [0x43Cc8AD0c223b38D9c04802bB184A2D97e497D38](https://etherscan.io/address/0x43Cc8AD0c223b38D9c04802bB184A2D97e497D38) | +| stableDebtTokenImpl | [0x15C5620dfFaC7c7366EED66C20Ad222DDbB1eD57](https://etherscan.io/address/0x15C5620dfFaC7c7366EED66C20Ad222DDbB1eD57) | +| borrowingEnabled | true | +| stableBorrowRateEnabled | false | +| isBorrowableInIsolation | true | +| interestRateStrategy | [0x4011fcd421b9E90f131B164EC1d162DBE269621C](https://etherscan.io/address/0x4011fcd421b9E90f131B164EC1d162DBE269621C) | +| liquidityIndex | 1 | +| variableBorrowIndex | 1 | +| aTokenName | Aave Ethereum USDe | +| aTokenSymbol | aEthUSDe | +| currentLiquidityRate | 0 % | +| currentVariableBorrowRate | 0 % | +| isPaused | false | +| stableDebtTokenName | Aave Ethereum Stable Debt USDe | +| stableDebtTokenSymbol | stableDebtEthUSDe | +| variableDebtTokenName | Aave Ethereum Variable Debt USDe | +| variableDebtTokenSymbol | variableDebtEthUSDe | +| optimalUsageRatio | 80 % | +| maxExcessStableToTotalDebtRatio | 100 % | +| maxExcessUsageRatio | 20 % | +| optimalStableToTotalDebtRatio | 0 % | +| baseVariableBorrowRate | 0 % | +| variableRateSlope1 | 9 % | +| variableRateSlope2 | 75 % | +| baseStableBorrowRate | 9 % | +| stableRateSlope1 | 9 % | +| stableRateSlope2 | 75 % | +| interestRate | ![ir](/.assets/a2ff7054b21a6d938826bbea32b5e589c6a0c8f7.svg) | + + +## Raw diff + +```json +{ + "reserves": { + "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3": { + "from": null, + "to": { + "aToken": "0x4F5923Fc5FD4a93352581b38B7cD26943012DECF", + "aTokenImpl": "0x7EfFD7b47Bfd17e52fB7559d3f924201b9DbfF3d", + "aTokenName": "Aave Ethereum USDe", + "aTokenSymbol": "aEthUSDe", + "borrowCap": 72000000, + "borrowingEnabled": true, + "currentLiquidityRate": 0, + "currentVariableBorrowRate": 0, + "debtCeiling": 4000000000, + "decimals": 18, + "eModeCategory": 0, + "interestRateStrategy": "0x4011fcd421b9E90f131B164EC1d162DBE269621C", + "isActive": true, + "isBorrowableInIsolation": true, + "isFlashloanable": true, + "isFrozen": false, + "isPaused": false, + "isSiloed": false, + "liquidationBonus": 10850, + "liquidationProtocolFee": 1000, + "liquidationThreshold": 7500, + "liquidityIndex": "1000000000000000000000000000", + "ltv": 7200, + "oracle": "0x55B6C4D3E8A27b8A1F5a263321b602e0fdEEcC17", + "oracleDecimals": 8, + "oracleDescription": "Capped USDe / USD", + "oracleLatestAnswer": 100079999, + "reserveFactor": 2500, + "stableBorrowRateEnabled": false, + "stableDebtToken": "0x43Cc8AD0c223b38D9c04802bB184A2D97e497D38", + "stableDebtTokenImpl": "0x15C5620dfFaC7c7366EED66C20Ad222DDbB1eD57", + "stableDebtTokenName": "Aave Ethereum Stable Debt USDe", + "stableDebtTokenSymbol": "stableDebtEthUSDe", + "supplyCap": 80000000, + "symbol": "USDe", + "underlying": "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3", + "usageAsCollateralEnabled": true, + "variableBorrowIndex": "1000000000000000000000000000", + "variableDebtToken": "0x015396E1F286289aE23a762088E863b3ec465145", + "variableDebtTokenImpl": "0xaC725CB59D16C81061BDeA61041a8A5e73DA9EC6", + "variableDebtTokenName": "Aave Ethereum Variable Debt USDe", + "variableDebtTokenSymbol": "variableDebtEthUSDe" + } + } + }, + "strategies": { + "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3": { + "from": null, + "to": { + "address": "0x4011fcd421b9E90f131B164EC1d162DBE269621C", + "baseStableBorrowRate": "90000000000000000000000000", + "baseVariableBorrowRate": 0, + "maxExcessStableToTotalDebtRatio": "1000000000000000000000000000", + "maxExcessUsageRatio": "200000000000000000000000000", + "optimalStableToTotalDebtRatio": 0, + "optimalUsageRatio": "800000000000000000000000000", + "stableRateSlope1": "90000000000000000000000000", + "stableRateSlope2": "750000000000000000000000000", + "variableRateSlope1": "90000000000000000000000000", + "variableRateSlope2": "750000000000000000000000000" + } + } + } +} +``` \ No newline at end of file diff --git a/diffs/AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528_before_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528_after.md b/diffs/AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528_before_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528_after.md new file mode 100644 index 000000000..73fbe8254 --- /dev/null +++ b/diffs/AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528_before_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528_after.md @@ -0,0 +1,57 @@ +## Reserve changes + +### Reserves altered + +#### sUSD ([0x8c6f28f2F1A3C87F0f938b96d27520d9751ec8d9](https://optimistic.etherscan.io/address/0x8c6f28f2F1A3C87F0f938b96d27520d9751ec8d9)) + +| description | value before | value after | +| --- | --- | --- | +| isFrozen | true | false | +| supplyCap | 20,000,000 sUSD | 7,000,000 sUSD | +| borrowCap | 13,000,000 sUSD | 5,600,000 sUSD | +| ltv | 0 % | 60 % | +| liquidationThreshold | 75 % | 70 % | + + +## Raw diff + +```json +{ + "eModes": { + "1": { + "liquidationThreshold": { + "from": 9500, + "to": 9300 + }, + "ltv": { + "from": 9300, + "to": 9000 + } + } + }, + "reserves": { + "0x8c6f28f2F1A3C87F0f938b96d27520d9751ec8d9": { + "borrowCap": { + "from": 13000000, + "to": 5600000 + }, + "isFrozen": { + "from": true, + "to": false + }, + "liquidationThreshold": { + "from": 7500, + "to": 7000 + }, + "ltv": { + "from": 0, + "to": 6000 + }, + "supplyCap": { + "from": 20000000, + "to": 7000000 + } + } + } +} +``` \ No newline at end of file diff --git a/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/AaveV3Ethereum_OrbitProgramRenewal_20240513.sol b/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/AaveV3Ethereum_OrbitProgramRenewal_20240513.sol new file mode 100644 index 000000000..ca0af2393 --- /dev/null +++ b/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/AaveV3Ethereum_OrbitProgramRenewal_20240513.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol'; +import {AaveV3Ethereum, AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol'; + +import {OrbitProgramData} from './OrbitProgramData.sol'; +import {IProposalGenericExecutor} from 'aave-helpers/interfaces/IProposalGenericExecutor.sol'; + +/// Helper interface to withdraw ETH +interface IWETH { + function withdraw(uint256) external; +} + +/** + * @title Orbit Program Renewal + * @author Aave Chan Initiative + * - Snapshot: "https://snapshot.org/#/aave.eth/proposal/0x4a10e2a8ca95024d7cf0791aa82ed262c816ff0ee78bc2f3ab3487e70d731361" + * - Discussion: https://governance.aave.com/t/arfc-orbit-program-renewal-may-2024/17683 + */ +contract AaveV3Ethereum_OrbitProgramRenewal_20240513 is IProposalGenericExecutor { + error EthTransferFailed(address account); + function execute() external { + // custom code goes here + AaveV3Ethereum.COLLECTOR.transfer( + AaveV3EthereumAssets.WETH_UNDERLYING, + address(this), + OrbitProgramData.TOTAL_WETH_REBATE + ); + + IWETH(AaveV3EthereumAssets.WETH_UNDERLYING).withdraw(OrbitProgramData.TOTAL_WETH_REBATE); + + OrbitProgramData.GasUsage[] memory usage = OrbitProgramData.getGasUsageData(); + uint256 usageLength = usage.length; + for (uint256 i = 0; i < usageLength; i++) { + (bool ok, ) = usage[i].account.call{value: usage[i].usage}(''); + if (!ok) revert EthTransferFailed(usage[i].account); + } + + uint256 actualStreamAmount = (OrbitProgramData.STREAM_AMOUNT / + OrbitProgramData.STREAM_DURATION) * OrbitProgramData.STREAM_DURATION; + + address[] memory orbitAddresses = OrbitProgramData.getOrbitAddresses(); + uint256 orbitAddressesLength = orbitAddresses.length; + for (uint256 i = 0; i < orbitAddressesLength; i++) { + AaveV3Ethereum.COLLECTOR.createStream( + orbitAddresses[i], + actualStreamAmount, + AaveV3EthereumAssets.GHO_UNDERLYING, + block.timestamp, + block.timestamp + OrbitProgramData.STREAM_DURATION + ); + } + } + receive() external payable {} +} diff --git a/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/AaveV3Ethereum_OrbitProgramRenewal_20240513.t.sol b/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/AaveV3Ethereum_OrbitProgramRenewal_20240513.t.sol new file mode 100644 index 000000000..a4d06dcd5 --- /dev/null +++ b/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/AaveV3Ethereum_OrbitProgramRenewal_20240513.t.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {AaveV3Ethereum, AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol'; + +import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol'; +import 'forge-std/Test.sol'; +import {ProtocolV3TestBase, ReserveConfig} from 'aave-helpers/ProtocolV3TestBase.sol'; +import {AaveV3Ethereum_OrbitProgramRenewal_20240513} from './AaveV3Ethereum_OrbitProgramRenewal_20240513.sol'; + +import {OrbitProgramData} from './OrbitProgramData.sol'; +/** + * @dev Test for AaveV3Ethereum_OrbitProgramRenewal_20240513 + * command: FOUNDRY_PROFILE=mainnet forge test --match-path=src/20240513_AaveV3Ethereum_OrbitProgramRenewal/AaveV3Ethereum_OrbitProgramRenewal_20240513.t.sol -vv + */ +contract AaveV3Ethereum_OrbitProgramRenewal_20240513_Test is ProtocolV3TestBase { + AaveV3Ethereum_OrbitProgramRenewal_20240513 internal proposal; + + function setUp() public { + vm.createSelectFork(vm.rpcUrl('mainnet'), 19862601); + proposal = new AaveV3Ethereum_OrbitProgramRenewal_20240513(); + } + + /** + * @dev executes the generic test suite including e2e and config snapshots + */ + function test_defaultProposalExecution() public { + uint256 collectorWethBalanceBefore = IERC20(AaveV3EthereumAssets.WETH_UNDERLYING).balanceOf( + address(AaveV3Ethereum.COLLECTOR) + ); + + uint256[] memory ethBalancesBeforeUsers = new uint256[](7); + OrbitProgramData.GasUsage[] memory usage = OrbitProgramData.getGasUsageData(); + for (uint256 i = 0; i < usage.length; i++) { + ethBalancesBeforeUsers[i] = usage[i].account.balance; + } + + uint256[] memory ghoBalancesBeforeUsers = new uint256[](4); + address[] memory ghoPaymentAddresses = OrbitProgramData.getOrbitAddresses(); + for (uint256 i = 0; i < ghoPaymentAddresses.length; i++) { + ghoBalancesBeforeUsers[i] = IERC20(AaveV3EthereumAssets.GHO_UNDERLYING).balanceOf( + ghoPaymentAddresses[i] + ); + } + + uint256 nextStreamId = AaveV3Ethereum.COLLECTOR.getNextStreamId(); + vm.expectRevert(); + AaveV3Ethereum.COLLECTOR.getStream(nextStreamId); + + executePayload(vm, address(proposal)); + + assertEq( + IERC20(AaveV3EthereumAssets.WETH_UNDERLYING).balanceOf(address(AaveV3Ethereum.COLLECTOR)), + collectorWethBalanceBefore - OrbitProgramData.TOTAL_WETH_REBATE, + 'WETH balance of Collector is not equal to previous minus to withdraw' + ); + + for (uint256 i = 0; i < usage.length; i++) { + assertGt( + usage[i].account.balance, + ethBalancesBeforeUsers[i], + 'REBATE recipient balance is not greater than before' + ); + } + + vm.warp(block.timestamp + 7 days); + + /// Their GHO balance has increased and call also withdraw from stream as it now exists + for (uint256 i = 0; i < ghoPaymentAddresses.length; i++) { + assertEq( + IERC20(AaveV3EthereumAssets.GHO_UNDERLYING).balanceOf(ghoPaymentAddresses[i]), + ghoBalancesBeforeUsers[i], + 'GHO balance of Orbit recipient is not greater than before' + ); + + vm.prank(ghoPaymentAddresses[i]); + AaveV3Ethereum.COLLECTOR.withdrawFromStream(nextStreamId + i, 1); + assertEq( + IERC20(AaveV3EthereumAssets.GHO_UNDERLYING).balanceOf(ghoPaymentAddresses[i]), + ghoBalancesBeforeUsers[i] + 1 + ); + } + } +} diff --git a/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/OrbitProgramData.sol b/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/OrbitProgramData.sol new file mode 100644 index 000000000..ace69ca96 --- /dev/null +++ b/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/OrbitProgramData.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +library OrbitProgramData { + struct GasUsage { + address account; + uint256 usage; + } + + uint256 public constant STREAM_DURATION = 90 days; + uint256 public constant STREAM_AMOUNT = 15_000 ether; + uint256 public constant TOTAL_WETH_REBATE = 3.381 ether; + address public constant EZREAL = 0x8659D0BB123Da6D16D9394C7838BA286c2207d0E; + address public constant STABLE_LABS = 0xECC2a9240268BC7a26386ecB49E1Befca2706AC9; + address public constant SAUCY_BLOCK = 0x08651EeE3b78254653062BA89035b8F8AdF924CE; + address public constant ARETA = 0x8b37a5Af68D315cf5A64097D96621F64b5502a22; + + address public constant ACI = 0x57ab7ee15cE5ECacB1aB84EE42D5A9d0d8112922; + address public constant TOKEN_LOGIC = 0x2cc1ADE245020FC5AAE66Ad443e1F66e01c54Df1; + + function getGasUsageData() internal pure returns (GasUsage[] memory) { + GasUsage[] memory usage = new GasUsage[](2); + usage[0] = GasUsage(ACI, 2.74 ether); + usage[1] = GasUsage(TOKEN_LOGIC, 0.641 ether); + + return usage; + } + + function getOrbitAddresses() internal pure returns (address[] memory) { + address[] memory streamAddresses = new address[](4); + streamAddresses[0] = EZREAL; + streamAddresses[1] = STABLE_LABS; + streamAddresses[2] = SAUCY_BLOCK; + streamAddresses[3] = ARETA; + + return streamAddresses; + } +} diff --git a/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/OrbitProgramRenewal.md b/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/OrbitProgramRenewal.md new file mode 100644 index 000000000..116cf69cf --- /dev/null +++ b/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/OrbitProgramRenewal.md @@ -0,0 +1,45 @@ +--- +title: "Orbit Program Renewal" +author: "Aave Chan Initiative" +discussions: "https://governance.aave.com/t/arfc-orbit-program-renewal-may-2024/17683" +snapshot: "https://snapshot.org/#/aave.eth/proposal/0x4a10e2a8ca95024d7cf0791aa82ed262c816ff0ee78bc2f3ab3487e70d731361" +--- + +## Simple Summary + +Proposing the renewal of the Orbit program for recognized delegates, compensating them with GHO and ETH reimbursement of Gas costs associated with their governance activity. + +## Motivation + +Orbit recognizes the added value of the Delegates in the decentralization & diversity of the Aave DAO. This compensation allows them to focus on aave and keep their contribution efforts to our governance. The ACI proposes the extension of Orbit for a new quarter. + +With the transition to Governance V3, a significant feature introduced is gasless voting via Gelato integration on the [DAO-run governance app](https://vote.onaave.com), making it easier for delegates to participate without the burden of gas costs. This innovation prompts the proposal to discontinue the general gas rebate program. However, recognizing the continued necessity for proposal creation and payload deployment activities, we propose maintaining targeted gas rebates for these specific actions. + +## Specification + +- **Period Coverage:** Blocks 19162697 (5th Feb 2024) to Block 19860031 (May 13th 2024) +- **Eligible Platforms:** + - EzR3al + - Stable Labs + - Saucy Block + - Areta +- **Gas Rebate:** Since this period is entirely covered by Governance V3, the Orbit program does not reimburse delegate vote gas as their vote is now subsidized by Gelato. We will continue to reimburse Service Providers for their Governance-related activity: + - ACI : 2.74 ETH + - TokenLogic : 0.641 ETH +- **Budget:** 60000 GHO and 3.381 ETH +- **Relevant Links:** + + - [Script output ](https://aavechan.notion.site/Gov-V3-May-2024-Script-Output-af8acc9d53874444b9a576e2329da28a) + +- [ACI’s Orbit tracker ](https://apps.aavechan.com/orbit-tracker) + +## References + +- Implementation: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/97b44a67ed311df87102abca1944712f56b14785/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/AaveV3Ethereum_OrbitProgramRenewal_20240513.sol) +- Tests: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/97b44a67ed311df87102abca1944712f56b14785/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/AaveV3Ethereum_OrbitProgramRenewal_20240513.t.sol) +- [Snapshot](https://snapshot.org/#/aave.eth/proposal/0x4a10e2a8ca95024d7cf0791aa82ed262c816ff0ee78bc2f3ab3487e70d731361) +- [Discussion](https://governance.aave.com/t/arfc-orbit-program-renewal-may-2024/17683) + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/OrbitProgramRenewal_20240513.s.sol b/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/OrbitProgramRenewal_20240513.s.sol new file mode 100644 index 000000000..756a9315b --- /dev/null +++ b/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/OrbitProgramRenewal_20240513.s.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {GovV3Helpers, IPayloadsControllerCore, PayloadsControllerUtils} from 'aave-helpers/GovV3Helpers.sol'; +import {GovernanceV3Ethereum} from 'aave-address-book/GovernanceV3Ethereum.sol'; +import {EthereumScript} from 'aave-helpers/ScriptUtils.sol'; +import {AaveV3Ethereum_OrbitProgramRenewal_20240513} from './AaveV3Ethereum_OrbitProgramRenewal_20240513.sol'; + +/** + * @dev Deploy Ethereum + * deploy-command: make deploy-ledger contract=src/20240513_AaveV3Ethereum_OrbitProgramRenewal/OrbitProgramRenewal_20240513.s.sol:DeployEthereum chain=mainnet + * verify-command: FOUNDRY_PROFILE=mainnet npx catapulta-verify -b broadcast/OrbitProgramRenewal_20240513.s.sol/1/run-latest.json + */ +contract DeployEthereum is EthereumScript { + function run() external broadcast { + // deploy payloads + address payload0 = GovV3Helpers.deployDeterministic( + type(AaveV3Ethereum_OrbitProgramRenewal_20240513).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/20240513_AaveV3Ethereum_OrbitProgramRenewal/OrbitProgramRenewal_20240513.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_OrbitProgramRenewal_20240513).creationCode + ); + payloads[0] = GovV3Helpers.buildMainnetPayload(vm, actionsEthereum); + + // create proposal + vm.startBroadcast(); + GovV3Helpers.createProposal( + vm, + payloads, + GovernanceV3Ethereum.VOTING_PORTAL_ETH_POL, + GovV3Helpers.ipfsHashFile( + vm, + 'src/20240513_AaveV3Ethereum_OrbitProgramRenewal/OrbitProgramRenewal.md' + ) + ); + } +} diff --git a/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/config.ts b/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/config.ts new file mode 100644 index 000000000..e43dc5b0d --- /dev/null +++ b/src/20240513_AaveV3Ethereum_OrbitProgramRenewal/config.ts @@ -0,0 +1,15 @@ +import {ConfigFile} from '../../generator/types'; +export const config: ConfigFile = { + rootOptions: { + author: 'Aave Chan Initiative', + pools: ['AaveV3Ethereum'], + title: 'Orbit Program Renewal', + shortName: 'OrbitProgramRenewal', + date: '20240513', + discussion: 'https://governance.aave.com/t/arfc-orbit-program-renewal-may-2024/17683', + snapshot: + 'https://snapshot.org/#/aave.eth/proposal/0x4a10e2a8ca95024d7cf0791aa82ed262c816ff0ee78bc2f3ab3487e70d731361', + votingNetwork: 'POLYGON', + }, + poolOptions: {AaveV3Ethereum: {configs: {OTHERS: {}}, cache: {blockNumber: 19862601}}}, +}; diff --git a/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528.sol b/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528.sol new file mode 100644 index 000000000..a80bf1632 --- /dev/null +++ b/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {AaveV3Ethereum, AaveV3EthereumEModes} from 'aave-address-book/AaveV3Ethereum.sol'; +import {AaveV3PayloadEthereum} from 'aave-helpers/v3-config-engine/AaveV3PayloadEthereum.sol'; +import {EngineFlags} from 'aave-helpers/v3-config-engine/EngineFlags.sol'; +import {IAaveV3ConfigEngine} from 'aave-helpers/v3-config-engine/IAaveV3ConfigEngine.sol'; +import {IV3RateStrategyFactory} from 'aave-helpers/v3-config-engine/IV3RateStrategyFactory.sol'; +import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol'; +import {SafeERC20} from 'solidity-utils/contracts/oz-common/SafeERC20.sol'; +/** + * @title Onboard USDe Aave V3 Ethereum + * @author ACI + * - Snapshot: https://snapshot.org/#/aave.eth/proposal/0xc1b6d0d390a2dabf81206f592f740c69163dd028dcb0f50182d0ad3a50e744b0 + * - Discussion: https://governance.aave.com/t/arfc-onboard-usde-to-aave-v3-on-ethereum/17690 + */ +contract AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528 is AaveV3PayloadEthereum { + using SafeERC20 for IERC20; + + address public constant USDe = 0x4c9EDD5852cd905f086C759E8383e09bff1E68B3; + uint256 public constant USDe_SEED_AMOUNT = 1e18; + + function _postExecute() internal override { + IERC20(USDe).forceApprove(address(AaveV3Ethereum.POOL), USDe_SEED_AMOUNT); + AaveV3Ethereum.POOL.supply(USDe, USDe_SEED_AMOUNT, address(AaveV3Ethereum.COLLECTOR), 0); + } + + function newListings() public pure override returns (IAaveV3ConfigEngine.Listing[] memory) { + IAaveV3ConfigEngine.Listing[] memory listings = new IAaveV3ConfigEngine.Listing[](1); + + listings[0] = IAaveV3ConfigEngine.Listing({ + asset: USDe, + assetSymbol: 'USDe', + priceFeed: 0x55B6C4D3E8A27b8A1F5a263321b602e0fdEEcC17, + eModeCategory: AaveV3EthereumEModes.NONE, + enabledToBorrow: EngineFlags.ENABLED, + stableRateModeEnabled: EngineFlags.DISABLED, + borrowableInIsolation: EngineFlags.ENABLED, + withSiloedBorrowing: EngineFlags.DISABLED, + flashloanable: EngineFlags.ENABLED, + ltv: 72_00, + liqThreshold: 75_00, + liqBonus: 8_50, + reserveFactor: 25_00, + supplyCap: 80_000_000, + borrowCap: 72_000_000, + debtCeiling: 40_000_000, + liqProtocolFee: 10_00, + rateStrategyParams: IV3RateStrategyFactory.RateStrategyParams({ + optimalUsageRatio: _bpsToRay(80_00), + baseVariableBorrowRate: _bpsToRay(0), + variableRateSlope1: _bpsToRay(9_00), + variableRateSlope2: _bpsToRay(75_00), + stableRateSlope1: _bpsToRay(9_00), + stableRateSlope2: _bpsToRay(75_00), + baseStableRateOffset: _bpsToRay(0), + stableRateExcessOffset: _bpsToRay(0), + optimalStableToTotalDebtRatio: _bpsToRay(0) + }) + }); + + return listings; + } +} diff --git a/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528.t.sol b/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528.t.sol new file mode 100644 index 000000000..ef5e40169 --- /dev/null +++ b/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528.t.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {GovV3Helpers} from 'aave-helpers/GovV3Helpers.sol'; +import {AaveV3Ethereum} from 'aave-address-book/AaveV3Ethereum.sol'; +import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol'; + +import 'forge-std/Test.sol'; +import {ProtocolV3TestBase, ReserveConfig} from 'aave-helpers/ProtocolV3TestBase.sol'; +import {AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528} from './AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528.sol'; + +/** + * @dev Test for AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528 + * command: FOUNDRY_PROFILE=mainnet forge test --match-path=src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528.t.sol -vv + */ +contract AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528_Test is ProtocolV3TestBase { + AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528 internal proposal; + + function setUp() public { + vm.createSelectFork(vm.rpcUrl('mainnet'), 19982323); + proposal = new AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528(); + } + + /** + * @dev executes the generic test suite including e2e and config snapshots + */ + function test_defaultProposalExecution() public { + defaultTest( + 'AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528', + AaveV3Ethereum.POOL, + address(proposal) + ); + } + + function test_collectorHasUSDeFunds() public { + GovV3Helpers.executePayload(vm, address(proposal)); + (address aTokenAddress, , ) = AaveV3Ethereum + .AAVE_PROTOCOL_DATA_PROVIDER + .getReserveTokensAddresses(proposal.USDe()); + assertGe(IERC20(aTokenAddress).balanceOf(address(AaveV3Ethereum.COLLECTOR)), 10 ** 18); + } +} diff --git a/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/OnboardUSDeAaveV3Ethereum.md b/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/OnboardUSDeAaveV3Ethereum.md new file mode 100644 index 000000000..ab62cdb72 --- /dev/null +++ b/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/OnboardUSDeAaveV3Ethereum.md @@ -0,0 +1,57 @@ +--- +title: "Onboard USDe Aave V3 Ethereum" +author: "ACI" +discussions: "https://governance.aave.com/t/arfc-onboard-usde-to-aave-v3-on-ethereum/17690" +snapshot: "https://snapshot.org/#/aave.eth/proposal/0xc1b6d0d390a2dabf81206f592f740c69163dd028dcb0f50182d0ad3a50e744b0" +--- + +## Simple Summary + +This proposal seek approval for the addition of USDe to Aave V3 on Ethereum + +## Motivation + +Ethena’s synthetic dollar, USDe, provides a stable crypto-native solution for a cash and carry structured product. The staked version of USDe, sUSDe, earns yield from the protocol and has high potential for strong borrow demand. + +## Specification + +The table below illustrates the configured risk parameters for **USDe** + +| Parameter | Value | +| ---------------------------------- | -----------------------------------------: | +| Isolation Mode | true | +| Borrowable | ENABLED | +| Collateral Enabled | true | +| Supply Cap (USDe) | 80,000,000 | +| Borrow Cap (USDe) | 72,000,000 | +| Debt Ceiling | USD 40,000,000 | +| LTV | 72 % | +| LT | 75 % | +| Liquidation Bonus | 8.5 % | +| Liquidation Protocol Fee | 10 % | +| Reserve Factor | 25 % | +| Base Variable Borrow Rate | 0 % | +| Variable Slope 1 | 9 % | +| Variable Slope 2 | 75 % | +| Uoptimal | 80 % | +| Stable Borrowing | DISABLED | +| Stable Slope1 | 9 % | +| Stable Slope2 | 75 % | +| Base Stable Rate Offset | 0 % | +| Stable Rate Excess Offset | 0 % | +| Optimal Stable To Total Debt Ratio | 0 % | +| Flashloanable | ENABLED | +| Siloed Borrowing | DISABLED | +| Borrowable in Isolation | ENABLED | +| Oracle | 0x55B6C4D3E8A27b8A1F5a263321b602e0fdEEcC17 | + +## References + +- Implementation: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/636bb0b17753c7e2af5d81933e7b61022e44e7e8/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528.sol) +- Tests: [AaveV3Ethereum](https://github.com/bgd-labs/aave-proposals-v3/blob/636bb0b17753c7e2af5d81933e7b61022e44e7e8/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528.t.sol) +- [Snapshot](https://snapshot.org/#/aave.eth/proposal/0xc1b6d0d390a2dabf81206f592f740c69163dd028dcb0f50182d0ad3a50e744b0) +- [Discussion](https://governance.aave.com/t/arfc-onboard-usde-to-aave-v3-on-ethereum/17690) + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/OnboardUSDeAaveV3Ethereum_20240528.s.sol b/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/OnboardUSDeAaveV3Ethereum_20240528.s.sol new file mode 100644 index 000000000..e8d117113 --- /dev/null +++ b/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/OnboardUSDeAaveV3Ethereum_20240528.s.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {GovV3Helpers, IPayloadsControllerCore, PayloadsControllerUtils} from 'aave-helpers/GovV3Helpers.sol'; +import {AaveV3Ethereum} from 'aave-address-book/AaveV3Ethereum.sol'; +import {GovernanceV3Ethereum} from 'aave-address-book/GovernanceV3Ethereum.sol'; +import {EthereumScript} from 'aave-helpers/ScriptUtils.sol'; +import {AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528} from './AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528.sol'; + +/** + * @dev Deploy Ethereum + * deploy-command: make deploy-ledger contract=src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/OnboardUSDeAaveV3Ethereum_20240528.s.sol:DeployEthereum chain=mainnet + * verify-command: FOUNDRY_PROFILE=mainnet npx catapulta-verify -b broadcast/OnboardUSDeAaveV3Ethereum_20240528.s.sol/1/run-latest.json + */ +contract DeployEthereum is EthereumScript { + function run() external broadcast { + // deploy payloads + address payload0 = GovV3Helpers.deployDeterministic( + type(AaveV3Ethereum_OnboardUSDeAaveV3Ethereum_20240528).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/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/OnboardUSDeAaveV3Ethereum_20240528.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_OnboardUSDeAaveV3Ethereum_20240528).creationCode + ); + payloads[0] = GovV3Helpers.buildMainnetPayload(vm, actionsEthereum); + + // create proposal + vm.startBroadcast(); + GovV3Helpers.createProposal( + vm, + payloads, + GovernanceV3Ethereum.VOTING_PORTAL_ETH_POL, + GovV3Helpers.ipfsHashFile( + vm, + 'src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/OnboardUSDeAaveV3Ethereum.md' + ) + ); + } +} diff --git a/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/config.ts b/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/config.ts new file mode 100644 index 000000000..34b29b0f6 --- /dev/null +++ b/src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/config.ts @@ -0,0 +1,55 @@ +import {ConfigFile} from '../../generator/types'; +export const config: ConfigFile = { + rootOptions: { + configFile: 'src/20240528_AaveV3Ethereum_OnboardUSDeAaveV3Ethereum/config.ts', + pools: ['AaveV3Ethereum'], + title: 'Onboard USDe Aave V3 Ethereum', + shortName: 'OnboardUSDeAaveV3Ethereum', + date: '20240528', + author: 'ACI', + discussion: 'https://governance.aave.com/t/arfc-onboard-usde-to-aave-v3-on-ethereum/17690', + snapshot: + 'https://snapshot.org/#/aave.eth/proposal/0xc1b6d0d390a2dabf81206f592f740c69163dd028dcb0f50182d0ad3a50e744b0', + votingNetwork: 'POLYGON', + }, + poolOptions: { + AaveV3Ethereum: { + configs: { + ASSET_LISTING: [ + { + assetSymbol: 'USDe', + decimals: 18, + priceFeed: '0x55B6C4D3E8A27b8A1F5a263321b602e0fdEEcC17', + ltv: '72', + liqThreshold: '75', + liqBonus: '8.5', + debtCeiling: '40000000', + liqProtocolFee: '10', + enabledToBorrow: 'ENABLED', + flashloanable: 'ENABLED', + stableRateModeEnabled: 'DISABLED', + borrowableInIsolation: 'ENABLED', + withSiloedBorrowing: 'DISABLED', + reserveFactor: '25', + supplyCap: '80000000', + borrowCap: '72000000', + rateStrategyParams: { + optimalUtilizationRate: '80', + baseVariableBorrowRate: '0', + variableRateSlope1: '9', + variableRateSlope2: '75', + stableRateSlope1: '9', + stableRateSlope2: '75', + baseStableRateOffset: '0', + stableRateExcessOffset: '0', + optimalStableToTotalDebtRatio: '0', + }, + eModeCategory: 'AaveV3EthereumEModes.NONE', + asset: '0x4c9edd5852cd905f086c759e8383e09bff1e68b3', + }, + ], + }, + cache: {blockNumber: 19967375}, + }, + }, +}; diff --git a/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.sol b/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.sol new file mode 100644 index 000000000..1cc0968cd --- /dev/null +++ b/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {AaveV3Optimism, AaveV3OptimismAssets, AaveV3OptimismEModes} from 'aave-address-book/AaveV3Optimism.sol'; +import {AaveV3PayloadOptimism} from 'aave-helpers/v3-config-engine/AaveV3PayloadOptimism.sol'; +import {EngineFlags} from 'aave-helpers/v3-config-engine/EngineFlags.sol'; +import {IAaveV3ConfigEngine} from 'aave-helpers/v3-config-engine/IAaveV3ConfigEngine.sol'; + +/** + * @title Chaos Labs Parameter Recommendations sUSD on V3 Optimism + * @author Chaos Labs + * - Snapshot: https://snapshot.org/#/aave.eth/proposal/0xa66afef5e247d9369831e874a60d022ce6b12645b41d9a244077a3a279ef24f3 + * - Discussion: https://governance.aave.com/t/arfc-chaos-labs-parameter-recommendations-susd-on-v3-optimism-05-232024/17779 + */ +contract AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528 is + AaveV3PayloadOptimism +{ + function _postExecute() internal override { + AaveV3Optimism.POOL_CONFIGURATOR.setReserveFreeze(AaveV3OptimismAssets.sUSD_UNDERLYING, false); + } + + function capsUpdates() public pure override returns (IAaveV3ConfigEngine.CapsUpdate[] memory) { + IAaveV3ConfigEngine.CapsUpdate[] memory capsUpdate = new IAaveV3ConfigEngine.CapsUpdate[](1); + + capsUpdate[0] = IAaveV3ConfigEngine.CapsUpdate({ + asset: AaveV3OptimismAssets.sUSD_UNDERLYING, + supplyCap: 7_000_000, + borrowCap: 5_600_000 + }); + + return capsUpdate; + } + + function collateralsUpdates() + public + pure + override + returns (IAaveV3ConfigEngine.CollateralUpdate[] memory) + { + IAaveV3ConfigEngine.CollateralUpdate[] + memory collateralUpdate = new IAaveV3ConfigEngine.CollateralUpdate[](1); + + collateralUpdate[0] = IAaveV3ConfigEngine.CollateralUpdate({ + asset: AaveV3OptimismAssets.sUSD_UNDERLYING, + ltv: 60_00, + liqThreshold: 70_00, + liqBonus: EngineFlags.KEEP_CURRENT, + debtCeiling: EngineFlags.KEEP_CURRENT, + liqProtocolFee: EngineFlags.KEEP_CURRENT + }); + + return collateralUpdate; + } + + function eModeCategoriesUpdates() + public + pure + override + returns (IAaveV3ConfigEngine.EModeCategoryUpdate[] memory) + { + IAaveV3ConfigEngine.EModeCategoryUpdate[] + memory eModeUpdates = new IAaveV3ConfigEngine.EModeCategoryUpdate[](1); + + eModeUpdates[0] = IAaveV3ConfigEngine.EModeCategoryUpdate({ + eModeCategory: AaveV3OptimismEModes.STABLECOINS, + ltv: 90_00, + liqThreshold: 93_00, + liqBonus: EngineFlags.KEEP_CURRENT, + priceSource: EngineFlags.KEEP_CURRENT_ADDRESS, + label: EngineFlags.KEEP_CURRENT_STRING + }); + + return eModeUpdates; + } +} diff --git a/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.t.sol b/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.t.sol new file mode 100644 index 000000000..476673f2e --- /dev/null +++ b/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.t.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {AaveV3Optimism} from 'aave-address-book/AaveV3Optimism.sol'; + +import 'forge-std/Test.sol'; +import {ProtocolV3TestBase, ReserveConfig} from 'aave-helpers/ProtocolV3TestBase.sol'; +import {AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528} from './AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.sol'; +import {AaveV3OptimismAssets} from 'aave-address-book/AaveV3Optimism.sol'; +import {DataTypes} from 'aave-address-book/AaveV3.sol'; + +/** + * @dev Test for AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528 + * command: FOUNDRY_PROFILE=optimism forge test --match-path=src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.t.sol -vv + */ +contract AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528_Test is + ProtocolV3TestBase +{ + AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528 internal proposal; + + function setUp() public { + vm.createSelectFork(vm.rpcUrl('optimism'), 120646741); + proposal = new AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528(); + } + + /** + * @dev executes the generic test suite including e2e and config snapshots + */ + function test_defaultProposalExecution() public { + (ReserveConfig[] memory allConfigsBefore, ReserveConfig[] memory allConfigsAfter) = defaultTest( + 'AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528', + AaveV3Optimism.POOL, + address(proposal) + ); + + address[] memory assetsChanged = new address[](1); + assetsChanged[0] = AaveV3OptimismAssets.sUSD_UNDERLYING; + + _noReservesConfigsChangesApartFrom(allConfigsBefore, allConfigsAfter, assetsChanged); + + ReserveConfig memory config = _findReserveConfig( + allConfigsAfter, + AaveV3OptimismAssets.sUSD_UNDERLYING + ); + assertEq(config.isFrozen, false); + assertEq(config.ltv, 60_00); + assertEq(config.liquidationThreshold, 70_00); + assertEq(config.borrowCap, 5_600_000); + assertEq(config.supplyCap, 7_000_000); + + DataTypes.EModeCategory memory eModeStablecoinCategory = AaveV3Optimism + .POOL + .getEModeCategoryData(1); + assertEq(eModeStablecoinCategory.ltv, 90_00); + assertEq(eModeStablecoinCategory.liquidationThreshold, 93_00); + } +} diff --git a/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/ChaosLabsParameterRecommendationsSUSDOnV3Optimism.md b/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/ChaosLabsParameterRecommendationsSUSDOnV3Optimism.md new file mode 100644 index 000000000..5f285980c --- /dev/null +++ b/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/ChaosLabsParameterRecommendationsSUSDOnV3Optimism.md @@ -0,0 +1,68 @@ +--- +title: "Chaos Labs Parameter Recommendations sUSD on V3 Optimism" +author: "Chaos Labs" +discussions: "https://governance.aave.com/t/arfc-chaos-labs-parameter-recommendations-susd-on-v3-optimism-05-232024/17779" +--- + +## Simple Summary + +Following sUSD’s depeg, after which the market was frozen on V3 Optimism, we provide an update and recommend future actions. + +## Motivation + +sUSD depegged on May 16, 2024, with its price reaching a low of 0.915 relative to USDC. As it was depegging, we provided a full analysis of the cause and a recommendation to freeze its Optimism market; sUSD has since repegged. + +Market Response to Freezing + +Following the market being frozen on May 16, we observed gradual withdrawals over the next four days, with about 1M sUSD withdrawn. However, starting May 20, withdrawals accelerated, and there are currently 5.16M sUSD deposited in the market. + +On the other hand, the sUSD borrowed has been relatively stable, decreasing from 4.3M sUSD at the time of the freeze to 4.17M sUSD now. This is despite sUSD remaining depegged until May 21, incentivizing users who borrowed the asset to repay their debt. + +Synthetix has also announced its transition plan for V3, which details how it will scale sUSD. These updates include expanding the collateral assets for sUSD from SNX alone to SNX, ETH, USDC, and other yield-generating collateral and governance-approved tokens. Additionally, the protocol has incentivized sUSD liquidity providers on Velodrome (Optimism; 10,000 OP tokens per week in the sUSD/USDC pool) and Curve (Ethereum; 20,000 SNX tokens per week in the sUSD/USDC/DAI/USDT pool); liquidity has begun to improve as a result of these incentives. + +sUSD Exposure on Aave + +sUSD is listed on Aave V3 Optimism as a frozen collateral asset and Aave V2 Ethereum as a frozen, non-collateral asset. Since the freeze on Optimism, we have observed a sharp decrease in value borrowed against sUSD, as well as the amount borrowed against sUSD in E-Mode. The reduction in E-Mode borrowed against is especially important, given the high LT afforded in this market. + +Recommendations + +Reduce Supply and Borrow Caps on Aave V3, Optimism: Given that the market’s size has decreased, as well as a decrease in on-chain supply — from 31M pre-freeze to 23.6M now — we recommend decreasing the supply and borrow caps ahead of unfreezing the asset. This will ensure that any future growth in the market is controlled and risk is minimized. + +We recommend setting the caps according to our initial listing methodology, in which we determine the amount of an asset that can be liquidated with slippage lower than the LB, set at 1% in the stablecoin E-mode, and recommend the supply cap be double that amount. This leads us to a recommendation of a 7M sUSD supply cap and a borrow cap set at 80% of the supply cap at 5.6M sUSD. +Reduce Stablecoin E-Mode LT and LTV: We recommend reducing E-Mode LT and LTV for stablecoins in Optimism’s Stablecoin E-Mode. Reducing LTs will make the protocol more resilient to any potential depegs in the future, ensuring that there is larger buffer in the event a stablecoin’s price falls and liquidations occur. Additionally, lowering LTV will slightly reduce users’ stablecoin-stablecoin borrowing power, again reducing risk in these markets. + +A 2% LT reduction on the Optimism V3 stablecoin E-mode category will make 18 accounts eligible for liquidation, potentially inducing $25K in new liquidations. +Adjust sUSD’s LTV and LT: Following the freeze of sUSD, its non-E-Mode LTV was dropped to 0%. Its current LT is 75%. Increasing the LTV will allow users to borrow non-stablecoin assets against their collateral, while adjusting the LT downwards will ensure the protocol has a larger buffer in the event of liquidations, whether from a depeg or from appreciation of borrowed assets. + +We recommend increasing sUSD’s non-E-Mode LTV to 60% and reducing its non-E-Mode LT to 70%. At this time, this would lead to a negligible $8 in liquidation across 4 accounts. +Unfreeze the sUSD market on Optimism: While sUSD has repegged, we note that the ongoing deprecation of synth assets may continue to cause peg volatility. The discount rate, which dictates the value synth asset holders can receive when they redeem, will continue to be lowered in an effort to deprecate these markets. Synth asset holders may request a redemption at parity, which, in the future, may carry some time-based conditions (i.e., sUSD is sent to the redeeming user over the course of weeks or months) to reduce the potential impact on sUSD’s peg. While the Synthetix Council has an incentive to ensure redemptions of synth assets with minimal price impacts, whether to the synth assets or sUSD, these time-based conditions are not codified. + +Given this, as well as the reduced supply/borrow caps and E-Mode LT/LTV, we recommend unfreezing the market. +We would like to thank @kaleb and the Synthetix team for their collaboration, insights on the situation, and guidance on the protocol and governance mechanisms to stabilize the peg. + +## Specification + +| Asset | Parameter | Current | Rec | +| ----- | ---------- | ---------- | --------- | +| sUSD | Supply cap | 20,000,000 | 7,000,000 | +| sUSD | Borrow cap | 13,000,000 | 5,600,000 | +| sUSD | LT | 75% | 70% | +| sUSD | LTV | 0.0% | 60% | + +Stablecoin E-Mode Specifications + +| Parameter | Current | Rec | +| --------- | ------- | --- | +| LT | 95% | 93% | +| LTV | 93% | 90% | + +## References + +- Implementation: [AaveV3Optimism](https://github.com/bgd-labs/aave-proposals-v3/blob/ad5c895c51906be7b3ab7d2e61e6570644f3cbf5/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.sol) +- Tests: [AaveV3Optimism](https://github.com/bgd-labs/aave-proposals-v3/blob/ad5c895c51906be7b3ab7d2e61e6570644f3cbf5/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.t.sol) +- [Snapshot](https://snapshot.org/#/aave.eth/proposal/0xa66afef5e247d9369831e874a60d022ce6b12645b41d9a244077a3a279ef24f3) +- [Discussion](https://governance.aave.com/t/arfc-chaos-labs-parameter-recommendations-susd-on-v3-optimism-05-232024/17779) + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.s.sol b/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.s.sol new file mode 100644 index 000000000..8547b8705 --- /dev/null +++ b/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.s.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {GovV3Helpers, IPayloadsControllerCore, PayloadsControllerUtils} from 'aave-helpers/GovV3Helpers.sol'; +import {GovernanceV3Ethereum} from 'aave-address-book/GovernanceV3Ethereum.sol'; +import {EthereumScript, OptimismScript} from 'aave-helpers/ScriptUtils.sol'; +import {AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528} from './AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.sol'; + +/** + * @dev Deploy Optimism + * deploy-command: make deploy-ledger contract=src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.s.sol:DeployOptimism chain=optimism + * verify-command: FOUNDRY_PROFILE=optimism npx catapulta-verify -b broadcast/ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.s.sol/10/run-latest.json + */ +contract DeployOptimism is OptimismScript { + function run() external broadcast { + // deploy payloads + address payload0 = GovV3Helpers.deployDeterministic( + type(AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528).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/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528.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 actionsOptimism = new IPayloadsControllerCore.ExecutionAction[](1); + actionsOptimism[0] = GovV3Helpers.buildAction( + type(AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism_20240528).creationCode + ); + payloads[0] = GovV3Helpers.buildOptimismPayload(vm, actionsOptimism); + + // create proposal + vm.startBroadcast(); + GovV3Helpers.createProposal( + vm, + payloads, + GovernanceV3Ethereum.VOTING_PORTAL_ETH_POL, + GovV3Helpers.ipfsHashFile( + vm, + 'src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/ChaosLabsParameterRecommendationsSUSDOnV3Optimism.md' + ) + ); + } +} diff --git a/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/config.ts b/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/config.ts new file mode 100644 index 000000000..40e98b4bf --- /dev/null +++ b/src/20240528_AaveV3Optimism_ChaosLabsParameterRecommendationsSUSDOnV3Optimism/config.ts @@ -0,0 +1,44 @@ +import {ConfigFile} from '../../generator/types'; +export const config: ConfigFile = { + rootOptions: { + pools: ['AaveV3Optimism'], + title: 'Chaos Labs Parameter Recommendations sUSD on V3 Optimism', + shortName: 'ChaosLabsParameterRecommendationsSUSDOnV3Optimism', + date: '20240528', + author: 'Chaos Labs', + discussion: + 'https://governance.aave.com/t/arfc-chaos-labs-parameter-recommendations-susd-on-v3-optimism-05-232024/17779', + snapshot: + 'https://snapshot.org/#/aave.eth/proposal/0xa66afef5e247d9369831e874a60d022ce6b12645b41d9a244077a3a279ef24f3', + votingNetwork: 'POLYGON', + }, + poolOptions: { + AaveV3Optimism: { + configs: { + CAPS_UPDATE: [{asset: 'sUSD', supplyCap: '7000000', borrowCap: '5600000'}], + COLLATERALS_UPDATE: [ + { + asset: 'sUSD', + ltv: '60', + liqThreshold: '70', + liqBonus: '', + debtCeiling: '', + liqProtocolFee: '', + }, + ], + EMODES_UPDATES: [ + { + eModeCategory: 'AaveV3OptimismEModes.STABLECOINS', + ltv: '90', + liqThreshold: '93', + liqBonus: '', + priceSource: '', + label: '', + }, + ], + FREEZE: [{asset: 'sUSD', shouldBeFrozen: false}], + }, + cache: {blockNumber: 120646741}, + }, + }, +};