diff --git a/src/20230926_AaveV3_Eth_GHOFunding/AaveV3_Ethereum_GHOFunding_20230926.sol b/src/20230926_AaveV3_Eth_GHOFunding/AaveV3_Ethereum_GHOFunding_20230926.sol new file mode 100644 index 00000000..e73a4f31 --- /dev/null +++ b/src/20230926_AaveV3_Eth_GHOFunding/AaveV3_Ethereum_GHOFunding_20230926.sol @@ -0,0 +1,111 @@ +// 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 {AaveV2Ethereum, AaveV2EthereumAssets} from 'aave-address-book/AaveV2Ethereum.sol'; +import {AaveSwapper} from 'aave-helpers/swaps/AaveSwapper.sol'; +import {AaveMisc} from 'aave-address-book/AaveMisc.sol'; +import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol'; + +/** + * @title GHO Funding + * @author TokenLogic + * - Snapshot: https://snapshot.org/#/aave.eth/proposal/0xb094cdc806d407d0cf4ea00e595ae95b8c145f77b77cce165c463326cc757639 + * - Discussion: https://governance.aave.com/t/arfc-treasury-management-gho-funding/14887/10 + */ +contract AaveV3_Ethereum_GHOFunding_20230926 is IProposalGenericExecutor { + + struct Asset { + address underlying; + address aToken; + address oracle; + uint256 amount; + } + + address public constant COLLECTOR = address(AaveV3Ethereum.COLLECTOR); + address public constant MILKMAN = 0x11C76AD590ABDFFCD980afEC9ad951B160F02797; + address public constant PRICE_CHECKER = 0xe80a1C615F75AFF7Ed8F08c9F21f9d00982D666c; + address public constant GHO_ORACLE = 0x3f12643D3f6f874d39C2a4c9f2Cd6f2DbAC877FC; + + function execute() external { + // DAI v2 + Asset memory DAIv2 = Asset({ + underlying: AaveV2EthereumAssets.DAI_UNDERLYING, + aToken: AaveV2EthereumAssets.DAI_A_TOKEN, + oracle: AaveV3EthereumAssets.DAI_ORACLE, + amount: IERC20(AaveV2EthereumAssets.DAI_A_TOKEN).balanceOf(COLLECTOR) + }); + + // DAI v3 + Asset memory DAIv3 = Asset({ + underlying: AaveV3EthereumAssets.DAI_UNDERLYING, + aToken: AaveV3EthereumAssets.DAI_A_TOKEN, + oracle: AaveV3EthereumAssets.DAI_ORACLE, + amount: 370_000 * 1e18 + }); + + // USDT v2 + Asset memory USDTv2 = Asset({ + underlying: AaveV2EthereumAssets.USDT_UNDERLYING, + aToken: AaveV2EthereumAssets.USDT_A_TOKEN, + oracle: 0x3E7d1eAB13ad0104d2750B8863b489D65364e32D, + amount: 370_000 * 1e6 + }); + + // BUSD + Asset memory BUSD = Asset({ + underlying: AaveV2EthereumAssets.BUSD_UNDERLYING, + aToken: address(0), // not used + oracle: 0x833D8Eb16D306ed1FbB5D7A2E019e106B960965A, + amount: IERC20(AaveV2EthereumAssets.BUSD_UNDERLYING).balanceOf(COLLECTOR) + }); + + // TUSD v2 + Asset memory TUSD = Asset({ + underlying: AaveV2EthereumAssets.TUSD_UNDERLYING, + aToken: address(0), // not used + oracle: 0xec746eCF986E2927Abd291a2A1716c940100f8Ba, + amount: IERC20(AaveV2EthereumAssets.TUSD_UNDERLYING).balanceOf(COLLECTOR) + }); + + + ////// DAI v2 & v3 swap ////// + AaveV3Ethereum.COLLECTOR.transfer(DAIv2.aToken, address(this), DAIv2.amount); + AaveV3Ethereum.COLLECTOR.transfer(DAIv3.aToken, address(this), DAIv3.amount); + uint256 daiAmount = + AaveV2Ethereum.POOL.withdraw(DAIv2.underlying, type(uint256).max, AaveMisc.AAVE_SWAPPER_ETHEREUM); + daiAmount += + AaveV3Ethereum.POOL.withdraw(DAIv3.underlying, type(uint256).max, AaveMisc.AAVE_SWAPPER_ETHEREUM); + swapAsset(DAIv2, daiAmount); + + ////// BUSD swap ////// + AaveV3Ethereum.COLLECTOR.transfer(BUSD.underlying, AaveMisc.AAVE_SWAPPER_ETHEREUM, BUSD.amount); + swapAsset(BUSD, BUSD.amount); + + ////// TUSD swap ////// + AaveV3Ethereum.COLLECTOR.transfer(TUSD.underlying, AaveMisc.AAVE_SWAPPER_ETHEREUM, TUSD.amount); + swapAsset(TUSD, TUSD.amount); + + ////// USDT v2 swap ////// + AaveV3Ethereum.COLLECTOR.transfer(USDTv2.aToken, address(this), USDTv2.amount); + uint256 usdtAmount = + AaveV2Ethereum.POOL.withdraw(USDTv2.underlying, type(uint256).max, AaveMisc.AAVE_SWAPPER_ETHEREUM); + swapAsset(USDTv2, usdtAmount); + } + + function swapAsset(Asset memory asset, uint256 amount) internal { + AaveSwapper swapper = AaveSwapper(AaveMisc.AAVE_SWAPPER_ETHEREUM); + swapper.swap( + MILKMAN, + PRICE_CHECKER, + asset.underlying, + AaveV3EthereumAssets.GHO_UNDERLYING, + asset.oracle, + GHO_ORACLE, + COLLECTOR, + amount, + 50 + ); + } +} diff --git a/src/20230926_AaveV3_Eth_GHOFunding/AaveV3_Ethereum_GHOFunding_20230926.t.sol b/src/20230926_AaveV3_Eth_GHOFunding/AaveV3_Ethereum_GHOFunding_20230926.t.sol new file mode 100644 index 00000000..aa88d6cd --- /dev/null +++ b/src/20230926_AaveV3_Eth_GHOFunding/AaveV3_Ethereum_GHOFunding_20230926.t.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import 'forge-std/Test.sol'; +import {GovHelpers} from 'aave-helpers/GovHelpers.sol'; +import {AaveGovernanceV2} from 'aave-address-book/AaveGovernanceV2.sol'; +import {ProtocolV3TestBase, ReserveConfig} from 'aave-helpers/ProtocolV3TestBase.sol'; +import {AaveV3_Ethereum_GHOFunding_20230926} from './AaveV3_Ethereum_GHOFunding_20230926.sol'; +import {AaveV2Ethereum, AaveV2EthereumAssets} from 'aave-address-book/AaveV2Ethereum.sol'; +import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol'; + +/** + * @dev Test for AaveV3_Ethereum_GHOFunding_20230926 + * command: make test-contract filter=AaveV3_Ethereum_GHOFunding_20230926 + */ +contract AaveV3_Ethereum_GHOFunding_20230926_Test is ProtocolV3TestBase { + AaveV3_Ethereum_GHOFunding_20230926 internal proposal; + + struct Swap { + address proxy; + address underlying; + uint256 amount; + } + + function setUp() public { + vm.createSelectFork(vm.rpcUrl('mainnet'), 18366393); + proposal = AaveV3_Ethereum_GHOFunding_20230926(0x121fE3fC3f617ACE9730203d2E27177131C4315e); + } + + function testProposalExecution() public { + address COLLECTOR = address(AaveV2Ethereum.COLLECTOR); + + Swap[4] memory swaps; + // milkman creates intermediary contract for each swap + // while swap is not executed the assets will be in these swap-specific proxy addresses instead of aaveSwapper + // proxy contracts addresses are deterministic, they could be derived via code. + // I simulated execution and copy pasted the address for simplicity + // see https://etherscan.io/address/0x11C76AD590ABDFFCD980afEC9ad951B160F02797#code#L878 + swaps[0] = Swap({ + proxy: 0x0eB322ac55dB67a5cA0810BA0eDae3501b1B7263, + underlying: AaveV2EthereumAssets.DAI_UNDERLYING, + amount: (370_000 * 1e18) + IERC20(AaveV2EthereumAssets.DAI_A_TOKEN).balanceOf(COLLECTOR) + }); + + swaps[1] = Swap({ + proxy: 0x8F2ca8bE5e06180d36117A8aE3f615837790d59B, + underlying: AaveV2EthereumAssets.BUSD_UNDERLYING, + amount: IERC20(AaveV2EthereumAssets.BUSD_UNDERLYING).balanceOf(COLLECTOR) + }); + + swaps[2] = Swap({ + proxy: 0xfEc76f65e943239E5A7CDC3CA6a89c26a0803FFd, + underlying: AaveV2EthereumAssets.TUSD_UNDERLYING, + amount: IERC20(AaveV2EthereumAssets.TUSD_UNDERLYING).balanceOf(COLLECTOR) + }); + + swaps[3] = Swap({ + proxy: 0x08dAB5c1F3AD03b1f2432Ab41eb161A6DBA1f338, + underlying: AaveV2EthereumAssets.USDT_UNDERLYING, + amount: 370_000 * 1e6 + }); + + GovHelpers.executePayload(vm, address(proposal), AaveGovernanceV2.SHORT_EXECUTOR); + + for(uint i = 0; i < swaps.length; i++) { + uint256 proxyBalanceAfter = IERC20(swaps[i].underlying).balanceOf(swaps[i].proxy); + assertEq(proxyBalanceAfter, swaps[i].amount); + } + + } +} diff --git a/src/20230926_AaveV3_Eth_GHOFunding/AaveV3_GHOFunding_20230926.s.sol b/src/20230926_AaveV3_Eth_GHOFunding/AaveV3_GHOFunding_20230926.s.sol new file mode 100644 index 00000000..47ee5e9e --- /dev/null +++ b/src/20230926_AaveV3_Eth_GHOFunding/AaveV3_GHOFunding_20230926.s.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {GovHelpers} from 'aave-helpers/GovHelpers.sol'; +import {EthereumScript} from 'aave-helpers/ScriptUtils.sol'; +import {AaveV3_Ethereum_GHOFunding_20230926} from './AaveV3_Ethereum_GHOFunding_20230926.sol'; + +/** + * @dev Deploy AaveV3_Ethereum_GHOFunding_20230926 + * command: make deploy-ledger contract=src/20230926_AaveV3_Eth_GHOFunding/AaveV3_GHOFunding_20230926.s.sol:DeployEthereum chain=mainnet + */ +contract DeployEthereum is EthereumScript { + function run() external broadcast { + new AaveV3_Ethereum_GHOFunding_20230926(); + } +} + +/** + * @dev Create Proposal + * command: make deploy-ledger contract=src/20230926_AaveV3_Eth_GHOFunding/AaveV3_GHOFunding_20230926.s.sol:CreateProposal chain=mainnet + */ +contract CreateProposal is EthereumScript { + function run() external broadcast { + GovHelpers.Payload[] memory payloads = new GovHelpers.Payload[](1); + payloads[0] = GovHelpers.buildMainnet(0x121fE3fC3f617ACE9730203d2E27177131C4315e); + GovHelpers.createProposal( + payloads, + GovHelpers.ipfsHashFile(vm, 'src/20230926_AaveV3_Eth_GHOFunding/GHOFunding.md') + ); + } +} diff --git a/src/20230926_AaveV3_Eth_GHOFunding/GHOFunding.md b/src/20230926_AaveV3_Eth_GHOFunding/GHOFunding.md new file mode 100644 index 00000000..5807e70b --- /dev/null +++ b/src/20230926_AaveV3_Eth_GHOFunding/GHOFunding.md @@ -0,0 +1,49 @@ +--- +title: "GHO Funding" +author: "TokenLogic" +discussions: "https://governance.aave.com/t/arfc-treasury-management-gho-funding/14887/10" +--- + +## Simple Summary + +This publication aims to acquire GHO from secondary markets to support the Aave DAO's short-term funding requirements. + +## Motivation + +The primary objective of this publication is to shift Aave DAO's expenditure towards being nominated in GHO. The following outlines some potential use cases for GHO: + +* 328,000 GHO allowance over 6 months [Aave Grants Continuation Proposal](https://governance.aave.com/t/temp-check-updated-aave-grants-continuation-proposal/14951) +* 550,000 GHO over 3 months[Aave Events & Sponsorship](https://governance.aave.com/t/temp-check-aave-events-sponsorship-budget/14953) +* 75,000 GHO over 3 months [Expansion of “Orbit”](https://governance.aave.com/t/arfc-expansion-of-orbit-a-dao-funded-delegate-platform-initiative/14785) +* 406,000 GHO over 3 months [GHO Liquidity Committee](https://governance.aave.com/t/temp-check-treasury-management-create-and-fund-gho-liquidity-committee/14800) +* TBA Future ACI Funding Request (Renewal mid-October) + +Totaling 1,359,000 GHO plus future ACI budget. + +This proposal is expected to acquire approximately $1.6M from secondary markets based on current holdings in the Ethereum Treasury. + +## Specification +Using the Aave Swap Contract, convert the following asset holdings to GHO: + +* [aDAI v2](https://etherscan.io/token/0x028171bca77440897b824ca71d1c56cac55b68a3?a=0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c) +* [TUSD](https://etherscan.io/address/0x0000000000085d4780B73119b644AE5ecd22b376?a=0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c) +* [BUSD](https://etherscan.io/token/0x4fabb145d64652a948d72533023f6e7a623c7c53?a=0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c) +* [370,000 aEthDAI v3](https://etherscan.io/token/0x018008bfb33d285247a21d44e50697654f754e63?a=0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c) +* [370,000 aUSDT v2](https://etherscan.io/token/0x3ed3b47dd13ec9a98b44e6204a523e766b225811?a=0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c) + +The GHO will be transferred to the [Aave Ethereum Treasury](https://etherscan.io/address/0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c). + +## References + +- Implementation: [Ethereum](https://github.com/bgd-labs/aave-proposals/blob/main/src/20230926_AaveV3_Eth_GHOFunding/AaveV3_Ethereum_GHOFunding_20230926.sol) +- Tests: [Ethereum](https://github.com/bgd-labs/aave-proposals/blob/main/src/20230926_AaveV3_Eth_GHOFunding/AaveV3_Ethereum_GHOFunding_20230926.t.sol) +- [Snapshot](https://snapshot.org/#/aave.eth/proposal/0xb094cdc806d407d0cf4ea00e595ae95b8c145f77b77cce165c463326cc757639) +- [Discussion](https://governance.aave.com/t/arfc-treasury-management-gho-funding/14887/10) + +# Disclosure + +TokenLogic receives no payment from Aave DAO or any external source for the creation of this proposal. TokenLogic is a delegate within the Aave ecosystem. + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).