Skip to content

Commit

Permalink
!feat: proposal creation helpers (#42)
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
- gov helpers no longer re-exports addresses, fetch them from address-book instead (https://github.com/bgd-labs/aave-address-book/blob/main/src/AaveGovernanceV2.sol)
- `createProposal` was renamed to `createTestProposal`
- the new `createProposal` is intended to be used for actual proposal creation and enforces delegatecall style proposals
  • Loading branch information
sakulstra authored Feb 2, 2023
1 parent e10aa98 commit 13a9871
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 19 deletions.
107 changes: 90 additions & 17 deletions src/GovHelpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {Vm} from 'forge-std/Vm.sol';
import {Test} from 'forge-std/Test.sol';
import {AaveGovernanceV2, IAaveGovernanceV2, IExecutorWithTimelock} from 'aave-address-book/AaveGovernanceV2.sol';
import {IPoolAddressesProvider} from 'aave-address-book/AaveV3.sol';
import {AaveMisc} from 'aave-address-book/AaveMisc.sol';
import {ProxyHelpers} from './ProxyHelpers.sol';

library GovHelpers {
Expand All @@ -19,24 +20,96 @@ library GovHelpers {
bytes32 ipfsHash;
}

IAaveGovernanceV2 internal constant GOV =
IAaveGovernanceV2(0xEC568fffba86c094cf06b22134B23074DFE2252c);
struct Payload {
address target;
string signature;
bytes callData;
}

address public constant SHORT_EXECUTOR = 0xEE56e2B3D491590B5b31738cC34d5232F378a8D5;
function buildMainnet(address payloadAddress) internal returns (Payload memory) {
require(
payloadAddress != AaveGovernanceV2.CROSSCHAIN_FORWARDER_OPTIMISM &&
payloadAddress != AaveGovernanceV2.CROSSCHAIN_FORWARDER_ARBITRUM &&
payloadAddress != AaveGovernanceV2.CROSSCHAIN_FORWARDER_POLYGON,
'PAYLOAD_CANT_BE_FORWARDER'
);

address public constant LONG_EXECUTOR = 0x79426A1c24B2978D90d7A5070a46C65B07bC4299;
return Payload({target: payloadAddress, signature: 'execute()', callData: ''});
}

address public constant AAVE = 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9;
function buildOptimism(address payloadAddress) internal returns (Payload memory) {
return
_buildL2({
forwarder: AaveGovernanceV2.CROSSCHAIN_FORWARDER_OPTIMISM,
payloadAddress: payloadAddress
});
}

address internal constant AAVE_WHALE = address(0x25F2226B597E8F9514B3F68F00f494cF4f286491);
function buildArbitrum(address payloadAddress) internal returns (Payload memory) {
return
_buildL2({
forwarder: AaveGovernanceV2.CROSSCHAIN_FORWARDER_ARBITRUM,
payloadAddress: payloadAddress
});
}

function buildPolygon(address payloadAddress) internal returns (Payload memory) {
return
_buildL2({
forwarder: AaveGovernanceV2.CROSSCHAIN_FORWARDER_POLYGON,
payloadAddress: payloadAddress
});
}

function _buildL2(address forwarder, address payloadAddress) private returns (Payload memory) {
return
Payload({
target: forwarder,
signature: 'execute(address)',
callData: abi.encode(payloadAddress)
});
}

function createProposal(Payload[] memory delegateCalls, bytes32 ipfsHash)
internal
returns (uint256)
{
require(block.chainid == 1, 'MAINNET_ONLY');
require(delegateCalls.length != 0, 'MINIMUM_ONE_PAYLOAD');
require(ipfsHash != bytes32(0), 'NON_ZERO_IPFS_HASH');

address[] memory targets = new address[](delegateCalls.length);
uint256[] memory values = new uint256[](delegateCalls.length);
string[] memory signatures = new string[](delegateCalls.length);
bytes[] memory calldatas = new bytes[](delegateCalls.length);
bool[] memory withDelegatecalls = new bool[](delegateCalls.length);
for (uint256 i = 0; i < delegateCalls.length; i++) {
targets[i] = delegateCalls[i].target;
signatures[i] = delegateCalls[i].signature;
calldatas[i] = delegateCalls[i].callData;
values[i] = 0;
withDelegatecalls[i] = true;
}

return
AaveGovernanceV2.GOV.create(
IExecutorWithTimelock(AaveGovernanceV2.SHORT_EXECUTOR),
targets,
values,
signatures,
calldatas,
withDelegatecalls,
ipfsHash
);
}

/**
* Impersonate the ecosystem reserve and created the proposal.
* @dev Impersonate the ecosystem reserve and creates the proposal.
*/
function createProposal(Vm vm, SPropCreateParams memory params) internal returns (uint256) {
vm.deal(AAVE_WHALE, 1 ether);
vm.startPrank(AAVE_WHALE);
uint256 proposalId = GOV.create(
function createTestProposal(Vm vm, SPropCreateParams memory params) internal returns (uint256) {
vm.deal(AaveMisc.ECOSYSTEM_RESERVE, 1 ether);
vm.startPrank(AaveMisc.ECOSYSTEM_RESERVE);
uint256 proposalId = AaveGovernanceV2.GOV.create(
IExecutorWithTimelock(params.executor),
params.targets,
params.values,
Expand All @@ -60,21 +133,21 @@ library GovHelpers {
function passVoteAndExecute(Vm vm, uint256 proposalId) internal {
uint256 power = 5000000 ether;
vm.roll(block.number + 1);
vm.store(address(GOV), _getProposalSlot(proposalId), bytes32(power));
uint256 endBlock = GOV.getProposalById(proposalId).endBlock;
vm.store(address(AaveGovernanceV2.GOV), _getProposalSlot(proposalId), bytes32(power));
uint256 endBlock = AaveGovernanceV2.GOV.getProposalById(proposalId).endBlock;
vm.roll(endBlock + 1);
GOV.queue(proposalId);
uint256 executionTime = GOV.getProposalById(proposalId).executionTime;
AaveGovernanceV2.GOV.queue(proposalId);
uint256 executionTime = AaveGovernanceV2.GOV.getProposalById(proposalId).executionTime;
vm.warp(executionTime + 1);
GOV.execute(proposalId);
AaveGovernanceV2.GOV.execute(proposalId);
}

function getProposalById(uint256 proposalId)
internal
view
returns (IAaveGovernanceV2.ProposalWithoutVotes memory)
{
return GOV.getProposalById(proposalId);
return AaveGovernanceV2.GOV.getProposalById(proposalId);
}
}

Expand Down
22 changes: 22 additions & 0 deletions src/test/GovTest.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import 'forge-std/Test.sol';
import {GovHelpers} from '../GovHelpers.sol';
import {AaveMisc} from 'aave-address-book/AaveMisc.sol';

contract GovernanceTest is Test {
function setUp() public {
vm.createSelectFork('mainnet', 16526807);
}

function testCreateProposal() public {
GovHelpers.Payload[] memory payloads = new GovHelpers.Payload[](2);
payloads[0] = GovHelpers.buildMainnet(address(1));
payloads[1] = GovHelpers.buildPolygon(address(2));

vm.startPrank(AaveMisc.ECOSYSTEM_RESERVE);
GovHelpers.createProposal(payloads, bytes32('ipfs'));
vm.stopPrank();
}
}
4 changes: 2 additions & 2 deletions src/test/ProxyHelpersTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
pragma solidity ^0.8.0;

import 'forge-std/Test.sol';
import {AaveGovernanceV2} from 'aave-address-book/AaveGovernanceV2.sol';
import {ProxyHelpers} from '../ProxyHelpers.sol';
import {GovHelpers} from '../GovHelpers.sol';

contract ProxyHelpersTest is Test {
function setUp() public {
Expand All @@ -15,7 +15,7 @@ contract ProxyHelpersTest is Test {
vm,
0x41A08648C3766F9F9d85598fF102a08f4ef84F84
);
assertEq(admin, GovHelpers.SHORT_EXECUTOR);
assertEq(admin, AaveGovernanceV2.SHORT_EXECUTOR);
}

function testImplementation() public {
Expand Down

0 comments on commit 13a9871

Please sign in to comment.