forked from bgd-labs/aave-proposals
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Marc Zeller
committed
Sep 26, 2023
1 parent
0ce7b46
commit 9cd495b
Showing
4 changed files
with
230 additions
and
0 deletions.
There are no files selected for viewing
35 changes: 35 additions & 0 deletions
35
...925_AaveV2_Eth_AaveTreasuryRWAAllocationPartI/AaveTreasuryRWAAllocationPartI.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
--- | ||
title: "Aave treasury RWA Allocation Part I" | ||
author: "Marc Zeller - Aave-Chan Initiative" | ||
discussions: "https://governance.aave.com/t/arfc-aave-treasury-rwa-allocation/14790" | ||
--- | ||
|
||
## Simple Summary | ||
|
||
This proposal is the first part of the Aave treasury RWA allocation. It proposes to allocate 50k USDC & 500 AAVE to Centrifuge. | ||
|
||
## Motivation | ||
|
||
Aave has long been a contributor and supporter of RWA initiatives. Since the first announcement of GHO, the Aave community has consistently expressed its interest in expanding into this area. Treasury Management at Aave has historically been focused on strategic crypto assets, ignoring the returns and liquidity available in offchain markets for various reasons. | ||
|
||
Today, with roughly 17% of the treasury in stablecoins (~13m USD), the Aave DAO is overlooking the 5% available interest in the risk-free rate of overnight financing of US treasury assets. This can offer $250,000 of recurring revenue a year at just 5m USD of investment. These markets can immediately become some of the highest earning revenue streams for the DAO. | ||
|
||
Beyond just economics, this proposal would allow the Aave DAO to establish and begin developing the internal RWA expertise necessary to engage with these markets. Centrifuge Prime is purpose-built for DeFi native organizations, offering the critical services and infrastructure necessary to onboard a diverse portfolio of RWA through a single interface. | ||
|
||
Centrifuge has a long track record of working with DAOs to bring RWA on as collateral, and pioneered the first Aave deployment into RWA with the joint development of the RWA Market. Onboarding Aave to Centrifuge Prime for liquid investment strategies is an optimal approach for scaling RWA with the Aave community. It will develop the legal and technical infrastructure necessary to interface with RWAs safely and efficiently, while allowing the Aave community to get comfortable and familiar with the processes and thinking around RWA. This will put Aave in a significantly improved position to be able to leverage RWA collateral for GHO in the long term, either to improve liquidity or develop additional revenue streams. | ||
|
||
## Specification | ||
|
||
This proposal withdraw 50k aUSDC from the Aave COLLECTOR contract and convert them to USDC before transferring them to the Centrifuge Treasury. | ||
This proposal also create a 500 AAVE stream for a period of two years to the Centrifuge Treasury. | ||
|
||
## References | ||
|
||
- Implementation: [Ethereum](https://github.com/bgd-labs/aave-proposals/blob/main/src/20230925_AaveV2_Eth_AaveTreasuryRWAAllocationPartI/AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925.sol) | ||
- Tests: [Ethereum](https://github.com/bgd-labs/aave-proposals/blob/main/src/20230925_AaveV2_Eth_AaveTreasuryRWAAllocationPartI/AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925.t.sol) | ||
- [Snapshot](https://snapshot.org/#/aave.eth/proposal/0x71db494e4b49e7533c5ccaa566686b2d045b0761cb3296a2d77af4b500566eb0) | ||
- [Discussion](https://governance.aave.com/t/arfc-aave-treasury-rwa-allocation/14790) | ||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). |
34 changes: 34 additions & 0 deletions
34
...2_Eth_AaveTreasuryRWAAllocationPartI/AaveV2_AaveTreasuryRWAAllocationPartI_20230925.s.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import {GovHelpers} from 'aave-helpers/GovHelpers.sol'; | ||
import {EthereumScript} from 'aave-helpers/ScriptUtils.sol'; | ||
import {AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925} from './AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925.sol'; | ||
|
||
/** | ||
* @dev Deploy AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925 | ||
* command: make deploy-ledger contract=src/20230925_AaveV2_Eth_AaveTreasuryRWAAllocationPartI/AaveV2_AaveTreasuryRWAAllocationPartI_20230925.s.sol:DeployEthereum chain=mainnet | ||
*/ | ||
contract DeployEthereum is EthereumScript { | ||
function run() external broadcast { | ||
new AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925(); | ||
} | ||
} | ||
|
||
/** | ||
* @dev Create Proposal | ||
* command: make deploy-ledger contract=src/20230925_AaveV2_Eth_AaveTreasuryRWAAllocationPartI/AaveV2_AaveTreasuryRWAAllocationPartI_20230925.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)); | ||
GovHelpers.createProposal( | ||
payloads, | ||
GovHelpers.ipfsHashFile( | ||
vm, | ||
'src/20230925_AaveV2_Eth_AaveTreasuryRWAAllocationPartI/AaveTreasuryRWAAllocationPartI.md' | ||
) | ||
); | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
...aveTreasuryRWAAllocationPartI/AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import {AaveMisc} from 'aave-address-book/AaveMisc.sol'; | ||
import {AaveV2Ethereum, AaveV2EthereumAssets} from 'aave-address-book/AaveV2Ethereum.sol'; | ||
import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol'; | ||
import {SafeERC20} from 'solidity-utils/contracts/oz-common/SafeERC20.sol'; | ||
|
||
/** | ||
* @title Aave treasury RWA Allocation Part I | ||
* @author Marc Zeller - Aave-Chan Initiative | ||
* - Snapshot: https://snapshot.org/#/aave.eth/proposal/0x71db494e4b49e7533c5ccaa566686b2d045b0761cb3296a2d77af4b500566eb0 | ||
* - Discussion: https://governance.aave.com/t/arfc-aave-treasury-rwa-allocation/14790 | ||
*/ | ||
contract AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925 { | ||
using SafeERC20 for IERC20; | ||
|
||
address public constant CENTRIFUGE = 0x9c489E4efba90A67299C1097a8628e233C33BB7B; // Placeholder until address is confirmed, DO NOT MERGE | ||
uint256 public constant STREAM_AMOUNT = 500e18; | ||
uint256 public constant STREAM_DURATION = 720 days; | ||
uint256 public constant ACTUAL_STREAM_AMOUNT_AAVE = | ||
(STREAM_AMOUNT / STREAM_DURATION) * STREAM_DURATION; | ||
uint256 public constant USDC_AMOUNT = 50_000e6; | ||
|
||
function execute() external { | ||
AaveV2Ethereum.COLLECTOR.transfer( | ||
AaveV2EthereumAssets.USDC_A_TOKEN, | ||
address(this), | ||
USDC_AMOUNT | ||
); | ||
|
||
// I needed to approve the transfer of USDC to CENTRIFUGE why? | ||
|
||
IERC20(AaveV2EthereumAssets.USDC_UNDERLYING).approve(address(this), USDC_AMOUNT); | ||
|
||
|
||
// withdraw aUSDC and convert it to USDC | ||
|
||
AaveV2Ethereum.POOL.withdraw( | ||
AaveV2EthereumAssets.USDC_UNDERLYING, | ||
type(uint256).max, | ||
address(this) | ||
); | ||
|
||
// transfer USDC to CENTRIFUGE | ||
|
||
IERC20(AaveV2EthereumAssets.USDC_UNDERLYING).safeTransferFrom( | ||
address(this), | ||
CENTRIFUGE, | ||
USDC_AMOUNT); | ||
|
||
// send back USDC dust to COLLECTOR | ||
|
||
IERC20(AaveV2EthereumAssets.USDC_UNDERLYING).approve(address(this), IERC20(AaveV2EthereumAssets.USDC_UNDERLYING).balanceOf(address(this))); | ||
|
||
|
||
IERC20(AaveV2EthereumAssets.USDC_UNDERLYING).safeTransferFrom( | ||
address(this), | ||
address(AaveV2Ethereum.COLLECTOR), | ||
IERC20(AaveV2EthereumAssets.USDC_UNDERLYING).balanceOf(address(this)) | ||
); | ||
|
||
// create AAVE stream for CENTRIFUGE | ||
AaveMisc.AAVE_ECOSYSTEM_RESERVE_CONTROLLER.createStream( | ||
AaveMisc.ECOSYSTEM_RESERVE, | ||
CENTRIFUGE, | ||
ACTUAL_STREAM_AMOUNT_AAVE, | ||
AaveV2EthereumAssets.AAVE_UNDERLYING, | ||
block.timestamp, | ||
block.timestamp + STREAM_DURATION | ||
); | ||
} | ||
} |
88 changes: 88 additions & 0 deletions
88
...eTreasuryRWAAllocationPartI/AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925.t.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// 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 {AaveMisc, IStreamable} from 'aave-address-book/AaveMisc.sol'; | ||
import {AaveV2Ethereum, AaveV2EthereumAssets} from 'aave-address-book/AaveV2Ethereum.sol'; | ||
import {ProtocolV2TestBase, ReserveConfig} from 'aave-helpers/ProtocolV2TestBase.sol'; | ||
import {AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925} from './AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925.sol'; | ||
import {IERC20} from 'solidity-utils/contracts/oz-common/interfaces/IERC20.sol'; | ||
|
||
/** | ||
* @dev Test for AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925 | ||
* command: make test-contract filter=AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925 | ||
*/ | ||
contract AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925_Test is ProtocolV2TestBase { | ||
AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925 internal proposal; | ||
|
||
address public constant CENTRIFUGE = 0x9c489E4efba90A67299C1097a8628e233C33BB7B; // Placeholder until address is confirmed, DO NOT MERGE | ||
address public constant USDC = AaveV2EthereumAssets.USDC_UNDERLYING; | ||
address public constant AAVE = AaveV2EthereumAssets.AAVE_UNDERLYING; | ||
address public constant AAVE_ECOSYSTEM_RESERVE = AaveMisc.ECOSYSTEM_RESERVE; | ||
IStreamable public constant STREAMABLE_AAVE_ECOSYSTEM_RESERVE = | ||
IStreamable(AAVE_ECOSYSTEM_RESERVE); | ||
uint256 public constant STREAM_AMOUNT = 500e18; | ||
uint256 public constant STREAM_DURATION = 720 days; | ||
uint256 public constant ACTUAL_STREAM_AMOUNT_AAVE = | ||
(STREAM_AMOUNT / STREAM_DURATION) * STREAM_DURATION; | ||
uint256 public constant USDC_AMOUNT = 50_000e6; | ||
|
||
function setUp() public { | ||
vm.createSelectFork(vm.rpcUrl('mainnet'), 18212877); | ||
proposal = new AaveV2_Ethereum_AaveTreasuryRWAAllocationPartI_20230925(); | ||
} | ||
|
||
function testProposalExecution() public { | ||
uint256 balanceBeforeStable = IERC20(USDC).balanceOf(CENTRIFUGE); | ||
|
||
uint256 balanceBeforeAave = IERC20(AAVE).balanceOf(CENTRIFUGE); | ||
|
||
uint256 nextEcosystemReserveStreamID = STREAMABLE_AAVE_ECOSYSTEM_RESERVE.getNextStreamId(); | ||
|
||
GovHelpers.executePayload(vm, address(proposal), AaveGovernanceV2.SHORT_EXECUTOR); | ||
|
||
uint256 balanceAfterStable = IERC20(USDC).balanceOf(CENTRIFUGE); | ||
|
||
assertApproxEqAbs(balanceAfterStable, balanceBeforeStable + USDC_AMOUNT, 1 ether); | ||
|
||
( | ||
address senderAave, | ||
address recipientAave, | ||
uint256 depositAave, | ||
address tokenAddressAave, | ||
uint256 startTimeAave, | ||
uint256 stopTimeAave, | ||
uint256 remainingBalanceAave, | ||
|
||
) = STREAMABLE_AAVE_ECOSYSTEM_RESERVE.getStream(nextEcosystemReserveStreamID); | ||
|
||
assertEq(senderAave, AAVE_ECOSYSTEM_RESERVE); | ||
assertEq(recipientAave, CENTRIFUGE); | ||
assertEq(depositAave, ACTUAL_STREAM_AMOUNT_AAVE); | ||
assertEq(tokenAddressAave, address(AAVE)); | ||
assertEq(stopTimeAave - startTimeAave, STREAM_DURATION); | ||
assertEq(remainingBalanceAave, ACTUAL_STREAM_AMOUNT_AAVE); | ||
|
||
vm.startPrank(CENTRIFUGE); | ||
vm.warp(block.timestamp + STREAM_DURATION + 1 days); | ||
|
||
uint256 currentAaveCENTRIFUGEStreamBalance = STREAMABLE_AAVE_ECOSYSTEM_RESERVE.balanceOf( | ||
nextEcosystemReserveStreamID, | ||
CENTRIFUGE | ||
); | ||
|
||
STREAMABLE_AAVE_ECOSYSTEM_RESERVE.withdrawFromStream( | ||
nextEcosystemReserveStreamID, | ||
currentAaveCENTRIFUGEStreamBalance | ||
); | ||
|
||
assertEq( | ||
IERC20(AAVE).balanceOf(CENTRIFUGE) >= balanceBeforeAave + ACTUAL_STREAM_AMOUNT_AAVE, | ||
true | ||
); | ||
|
||
vm.stopPrank(); | ||
} | ||
} |