Skip to content

Commit

Permalink
feat: Add sophhisticated defensive aave seed
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelmtzinf committed Jun 7, 2024
1 parent 17eb17c commit 7cb798d
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,6 @@ library Utils {
* 7. Seed Aave Pool
*/
contract AaveV3Arbitrum_GHOCrossChainLaunch_20240528 is AaveV3PayloadArbitrum {
using SafeERC20 for IERC20;

address public immutable GHO;
address public immutable GHO_IMPL;
address public immutable CCIP_TOKEN_POOL;
Expand Down Expand Up @@ -225,12 +223,59 @@ contract AaveV3Arbitrum_GHOCrossChainLaunch_20240528 is AaveV3PayloadArbitrum {
}

function _defensiveSeed() internal {
// Add Governance as Facilitator
IGhoToken(GHO).addFacilitator(address(this), 'Governance', uint128(Utils.GHO_SEED_AMOUNT));
AaveDefensiveSeed defensiveSeed = new AaveDefensiveSeed(GHO, Utils.GHO_SEED_AMOUNT);

// Add Facilitator and remove just after the mint of seed amount
uint256 seedAmount = defensiveSeed.DEFENSIVE_SEED_AMOUNT();
IGhoToken(GHO).addFacilitator(address(defensiveSeed), 'DefensiveSeed', uint128(seedAmount));
defensiveSeed.mint();
IGhoToken(GHO).setFacilitatorBucketCapacity(address(defensiveSeed), 0);
}
}

contract AaveDefensiveSeed {
using SafeERC20 for IERC20;

address public immutable GHO;
uint256 public immutable DEFENSIVE_SEED_AMOUNT;
bool public mintOnce;
bool public burnOnce;

constructor(address gho, uint256 seedAmount) {
GHO = gho;
DEFENSIVE_SEED_AMOUNT = seedAmount;
}

function mint() external {
require(!mintOnce, 'NOT_ACTIVE');

// mint
IGhoToken(GHO).mint(address(this), DEFENSIVE_SEED_AMOUNT);

// supply
IERC20(GHO).forceApprove(address(AaveV3Arbitrum.POOL), DEFENSIVE_SEED_AMOUNT);
AaveV3Arbitrum.POOL.supply(GHO, DEFENSIVE_SEED_AMOUNT, address(this), 0);

mintOnce = true;
}

function burn() external {
require(!burnOnce, 'NOT_ACTIVE');

// Check address(0) is aGHO holder
(address aGHO, , ) = AaveV3Arbitrum.AAVE_PROTOCOL_DATA_PROVIDER.getReserveTokensAddresses(GHO);
require(
IERC20(aGHO).balanceOf(address(0)) >= DEFENSIVE_SEED_AMOUNT,
'NOT_ENOUGH_DEFENSIVE_SEED'
);

// withdraw
uint256 amount = IERC20(aGHO).balanceOf(address(this));
AaveV3Arbitrum.POOL.withdraw(GHO, amount, address(this));

// burn
IGhoToken(GHO).burn(amount);

// Mint GHO and supply
IGhoToken(GHO).mint(address(this), Utils.GHO_SEED_AMOUNT);
IERC20(GHO).forceApprove(address(AaveV3Arbitrum.POOL), Utils.GHO_SEED_AMOUNT);
AaveV3Arbitrum.POOL.supply(GHO, Utils.GHO_SEED_AMOUNT, address(0), 0);
burnOnce = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {IPool} from 'ccip/v0.8/ccip/interfaces/pools/IPool.sol';
import {UpgradeableBurnMintTokenPool} from 'ccip/v0.8/ccip/pools/GHO/UpgradeableBurnMintTokenPool.sol';
import {IGhoToken} from 'gho-core/gho/interfaces/IGhoToken.sol';

import {AaveV3Arbitrum_GHOCrossChainLaunch_20240528, Utils} from './AaveV3Arbitrum_GHOCrossChainLaunch_20240528.sol';
import {AaveV3Arbitrum_GHOCrossChainLaunch_20240528, Utils, AaveDefensiveSeed} from './AaveV3Arbitrum_GHOCrossChainLaunch_20240528.sol';

/**
* @dev Test for AaveV3Arbitrum_GHOCrossChainLaunch_20240528
Expand Down Expand Up @@ -59,6 +59,76 @@ contract AaveV3Arbitrum_GHOCrossChainLaunch_20240528_Test is ProtocolV3TestBase
_validateCcipTokenPool();
}

event Supply(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
uint16 indexed referralCode
);
function test_defensiveAaveSeed() public {
vm.recordLogs();

GovV3Helpers.executePayload(vm, address(proposal));

// Fetch address
Vm.Log[] memory entries = vm.getRecordedLogs();
address defensiveSeed;
for (uint256 i = 0; i < entries.length; i++) {
if (entries[i].topics[0] == Supply.selector) {
(defensiveSeed, ) = abi.decode(entries[i].data, (address, uint256));
break;
}
}

// DefensiveSeed contract
assertEq(AaveDefensiveSeed(defensiveSeed).GHO(), address(GHO));
assertEq(AaveDefensiveSeed(defensiveSeed).DEFENSIVE_SEED_AMOUNT(), Utils.GHO_SEED_AMOUNT);
assertEq(AaveDefensiveSeed(defensiveSeed).mintOnce(), true);
assertEq(AaveDefensiveSeed(defensiveSeed).burnOnce(), false);

vm.expectRevert('NOT_ACTIVE');
AaveDefensiveSeed(defensiveSeed).mint();

// Seed state
(address aGHO, , ) = AaveV3Arbitrum.AAVE_PROTOCOL_DATA_PROVIDER.getReserveTokensAddresses(
address(GHO)
);
assertEq(GHO.totalSupply(), Utils.GHO_SEED_AMOUNT);
assertEq(IERC20(aGHO).totalSupply(), Utils.GHO_SEED_AMOUNT);
assertEq(IERC20(aGHO).balanceOf(address(0)), 0);
assertEq(IERC20(aGHO).balanceOf(defensiveSeed), Utils.GHO_SEED_AMOUNT);

(uint256 capacity, uint256 level) = GHO.getFacilitatorBucket(defensiveSeed);
assertEq(capacity, 0);
assertEq(level, Utils.GHO_SEED_AMOUNT);

// Wind down
vm.expectRevert('NOT_ENOUGH_DEFENSIVE_SEED');
AaveDefensiveSeed(defensiveSeed).burn();

// Someone burns some aGHO
vm.prank(address(TOKEN_POOL));
GHO.mint(address(this), Utils.GHO_SEED_AMOUNT);
assertEq(GHO.totalSupply(), Utils.GHO_SEED_AMOUNT * 2);
GHO.approve(address(AaveV3Arbitrum.POOL), Utils.GHO_SEED_AMOUNT);
AaveV3Arbitrum.POOL.supply(address(GHO), Utils.GHO_SEED_AMOUNT, address(0), 0);

AaveDefensiveSeed(defensiveSeed).burn();

vm.expectRevert('NOT_ACTIVE');
AaveDefensiveSeed(defensiveSeed).burn();

assertEq(GHO.totalSupply(), Utils.GHO_SEED_AMOUNT);
assertEq(IERC20(aGHO).totalSupply(), Utils.GHO_SEED_AMOUNT);
assertEq(IERC20(aGHO).balanceOf(address(0)), Utils.GHO_SEED_AMOUNT);
assertEq(IERC20(aGHO).balanceOf(defensiveSeed), 0);

(capacity, level) = GHO.getFacilitatorBucket(defensiveSeed);
assertEq(capacity, 0);
assertEq(level, 0);
}

/// @dev Test burn and mint actions, mocking CCIP calls
function test_ccipTokenPool() public {
GovV3Helpers.executePayload(vm, address(proposal));
Expand Down

0 comments on commit 7cb798d

Please sign in to comment.