-
Notifications
You must be signed in to change notification settings - Fork 30
Treasury Management - GHO Funding #323
Changes from 3 commits
ec33feb
7f7d5c0
efbd098
4269e5e
e0f309d
d4065ff
084eb9a
553296c
0fafb3c
70615a2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// 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'; | ||
import {SafeERC20} from 'solidity-utils/contracts/oz-common/SafeERC20.sol'; | ||
|
||
interface aTokenV1 { | ||
function redeem(uint256 _amount) external; | ||
} | ||
|
||
/** | ||
* @title GHO Funding | ||
* @author TokenLogic | ||
* - Snapshot: TODO | ||
sakulstra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* - Discussion: https://governance.aave.com/t/arfc-treasury-management-gho-funding/14887 | ||
sakulstra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
contract AaveV3_Ethereum_GHOFunding_20230926 is IProposalGenericExecutor { | ||
|
||
struct Asset { | ||
address underlying; | ||
address aToken; | ||
address oracle; | ||
uint256 amount; | ||
} | ||
|
||
function execute() external { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is this so unnecessarily imprecise? The forum post & snapshot said 1.6M Wouldn't it be better to just be exact? as there's not really a good reason not to be - you already have all the amount and could just make e.g. DAI on v3 fill the 1.6M. |
||
// DAI v2 | ||
Asset memory DAIv2 = Asset({ | ||
underlying: AaveV2EthereumAssets.DAI_UNDERLYING, | ||
aToken: AaveV2EthereumAssets.DAI_A_TOKEN, | ||
oracle: 0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not important, but AaveV3EthereumAssets.DAI_ORACLE could be used |
||
amount: IERC20(AaveV2EthereumAssets.DAI_A_TOKEN).balanceOf(address(AaveV3Ethereum.COLLECTOR)) | ||
}); | ||
|
||
// BUSD v2 | ||
Asset memory BUSDv2 = Asset({ | ||
underlying: AaveV2EthereumAssets.BUSD_UNDERLYING, | ||
aToken: AaveV2EthereumAssets.BUSD_A_TOKEN, | ||
oracle: 0x833D8Eb16D306ed1FbB5D7A2E019e106B960965A, | ||
amount: IERC20(AaveV2EthereumAssets.BUSD_A_TOKEN).balanceOf(address(AaveV3Ethereum.COLLECTOR)) | ||
}); | ||
|
||
// DAI v3 | ||
Asset memory DAIv3 = Asset({ | ||
underlying: AaveV3EthereumAssets.DAI_UNDERLYING, | ||
aToken: AaveV3EthereumAssets.DAI_A_TOKEN, | ||
oracle: 0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9, | ||
amount: 400_000 * 1e18 | ||
}); | ||
|
||
// USDT v2 | ||
Asset memory USDTv2 = Asset({ | ||
underlying: AaveV2EthereumAssets.USDT_UNDERLYING, | ||
aToken: AaveV2EthereumAssets.USDT_A_TOKEN, | ||
oracle: 0x3E7d1eAB13ad0104d2750B8863b489D65364e32D, | ||
amount: 1_100_000 * 1e6 | ||
}); | ||
|
||
// USDT v3 | ||
Asset memory USDTv3 = Asset({ | ||
underlying: AaveV3EthereumAssets.USDT_UNDERLYING, | ||
aToken: AaveV3EthereumAssets.USDT_A_TOKEN, | ||
oracle: 0x3E7d1eAB13ad0104d2750B8863b489D65364e32D, | ||
amount: 500_000 * 1e6 | ||
}); | ||
|
||
|
||
////// DAI v2 & v3 swap ////// | ||
AaveV3Ethereum.COLLECTOR.transfer(DAIv2.aToken, address(this), DAIv2.amount); | ||
AaveV3Ethereum.COLLECTOR.transfer(DAIv3.aToken, address(this), DAIv3.amount); | ||
uint256 swapperBalance = | ||
AaveV2Ethereum.POOL.withdraw(DAIv2.underlying, DAIv2.amount, AaveMisc.AAVE_SWAPPER_ETHEREUM); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this might revert if transfer is 1 wei short |
||
swapperBalance += | ||
AaveV3Ethereum.POOL.withdraw(DAIv3.underlying, DAIv3.amount, AaveMisc.AAVE_SWAPPER_ETHEREUM); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as well |
||
swapAsset(DAIv2, swapperBalance); | ||
|
||
////// BUSD v2 & v1 swap ////// | ||
// transfer max busd to payload | ||
swapperBalance = IERC20(BUSDv2.underlying).balanceOf(address(AaveV3Ethereum.COLLECTOR)); | ||
AaveV3Ethereum.COLLECTOR.transfer(BUSDv2.underlying, address (this), swapperBalance); | ||
// transfer specific amount of busdv2 to payload | ||
AaveV3Ethereum.COLLECTOR.transfer(BUSDv2.aToken, address(this), BUSDv2.amount); | ||
swapperBalance += AaveV2Ethereum.POOL.withdraw(BUSDv2.underlying, BUSDv2.amount, address(this)); | ||
|
||
SafeERC20.safeTransfer(IERC20(BUSDv2.underlying), AaveMisc.AAVE_SWAPPER_ETHEREUM, swapperBalance); | ||
swapAsset(BUSDv2, swapperBalance); | ||
|
||
////// USDT v2 & v3 swap ////// | ||
AaveV3Ethereum.COLLECTOR.transfer(USDTv2.aToken, address(this), USDTv2.amount); | ||
AaveV3Ethereum.COLLECTOR.transfer(USDTv3.aToken, address(this), USDTv3.amount); | ||
swapperBalance = | ||
sakulstra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
AaveV2Ethereum.POOL.withdraw(USDTv2.underlying, USDTv2.amount, AaveMisc.AAVE_SWAPPER_ETHEREUM); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as well |
||
swapperBalance += | ||
AaveV3Ethereum.POOL.withdraw(USDTv3.underlying, USDTv3.amount, AaveMisc.AAVE_SWAPPER_ETHEREUM); | ||
swapAsset(USDTv2, swapperBalance); | ||
} | ||
|
||
function swapAsset(Asset memory asset, uint256 amount) internal { | ||
address milkman = 0x11C76AD590ABDFFCD980afEC9ad951B160F02797; | ||
address priceChecker = 0xe80a1C615F75AFF7Ed8F08c9F21f9d00982D666c; | ||
address ghoOracle = 0x3f12643D3f6f874d39C2a4c9f2Cd6f2DbAC877FC; | ||
AaveSwapper swapper = AaveSwapper(AaveMisc.AAVE_SWAPPER_ETHEREUM); | ||
swapper.swap( | ||
milkman, | ||
priceChecker, | ||
asset.underlying, | ||
AaveV3EthereumAssets.GHO_UNDERLYING, | ||
asset.oracle, | ||
ghoOracle, | ||
address(AaveV3Ethereum.COLLECTOR), | ||
amount, | ||
50 | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// 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'), 18274396); | ||
proposal = new AaveV3_Ethereum_GHOFunding_20230926(); | ||
} | ||
|
||
function testProposalExecution() public { | ||
uint256 daiv2CollectorBalance = IERC20(AaveV2EthereumAssets.DAI_A_TOKEN).balanceOf(address(AaveV2Ethereum.COLLECTOR)); | ||
uint256 busdv2CollectorBalance = IERC20(AaveV2EthereumAssets.BUSD_A_TOKEN).balanceOf(address(AaveV2Ethereum.COLLECTOR)); | ||
uint256 busdCollectorBalance = IERC20(AaveV2EthereumAssets.BUSD_UNDERLYING).balanceOf(address(AaveV2Ethereum.COLLECTOR)); | ||
// uint256 tusdv2CollectorBalance = 75_800 * 1e18; | ||
Swap[3] 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: 0x2414B7eDd549E62e8a5877b73D96C80bAbC30bca, | ||
underlying: AaveV2EthereumAssets.DAI_UNDERLYING, | ||
amount: (400_000 * 1e18) + daiv2CollectorBalance | ||
}); | ||
swaps[1] = Swap({ | ||
proxy: 0x86487dad62c99A37d0052ed56BF1EafF2959294D, | ||
underlying: AaveV2EthereumAssets.BUSD_UNDERLYING, | ||
amount: busdv2CollectorBalance + busdCollectorBalance | ||
}); | ||
|
||
swaps[2] = Swap({ | ||
proxy: 0x3Df592eae98c2b4f312ADE339C01BBE2C8444618, | ||
underlying: AaveV2EthereumAssets.USDT_UNDERLYING, | ||
amount: 1_600_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); | ||
} | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(address(0)); // TODO | ||
GovHelpers.createProposal( | ||
payloads, | ||
GovHelpers.ipfsHashFile(vm, 'src/20230926_AaveV3_Eth_GHOFunding/GHOFunding.md') | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
--- | ||
title: "GHO Funding" | ||
author: "TokenLogic" | ||
discussions: "https://governance.aave.com/t/arfc-treasury-management-gho-funding/14887" | ||
sakulstra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
--- | ||
|
||
## 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) | ||
* [aBUSD v2](https://etherscan.io/token/0xa361718326c15715591c299427c62086f69923d9?a=0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c) | ||
* [BUSD](https://etherscan.io/token/0x4fabb145d64652a948d72533023f6e7a623c7c53?a=0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c) | ||
* [400,000 aEthDAI v3](https://etherscan.io/token/0x018008bfb33d285247a21d44e50697654f754e63?a=0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c) | ||
* [400,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) | ||
sakulstra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# 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/). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this interface is not used anywhere and could be removed