diff --git a/.gitmodules b/.gitmodules index 11a62babb..837cb4ae2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,6 +7,3 @@ [submodule "lib/aave-address-book"] path = lib/aave-address-book url = https://github.com/bgd-labs/aave-address-book -[submodule "lib/governance-crosschain-bridges"] - path = lib/governance-crosschain-bridges - url = https://github.com/aave/governance-crosschain-bridges diff --git a/lib/aave-address-book b/lib/aave-address-book index e1faa694a..17754972f 160000 --- a/lib/aave-address-book +++ b/lib/aave-address-book @@ -1 +1 @@ -Subproject commit e1faa694a800ae7b8c5b010b18c6ea0187839e92 +Subproject commit 17754972fcc15ea4ea15231308af22610f121d83 diff --git a/lib/forge-std b/lib/forge-std index 4513bc206..1d0766bc5 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 4513bc2063f23c57bee6558799584b518d387a39 +Subproject commit 1d0766bc5d814f117c7b1e643828f7d85024fb51 diff --git a/lib/governance-crosschain-bridges b/lib/governance-crosschain-bridges deleted file mode 160000 index 57dd43969..000000000 --- a/lib/governance-crosschain-bridges +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 57dd43969a68eb076fdbeae2953b572534694986 diff --git a/scripts/CrosschainForwarders.s.sol b/scripts/CrosschainForwarders.s.sol deleted file mode 100644 index a4fd05b76..000000000 --- a/scripts/CrosschainForwarders.s.sol +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import '../src/ScriptUtils.sol'; -import {CrosschainForwarderPolygon} from '../src/crosschainforwarders/CrosschainForwarderPolygon.sol'; -import {CrosschainForwarderOptimism} from '../src/crosschainforwarders/CrosschainForwarderOptimism.sol'; -import {CrosschainForwarderArbitrum} from '../src/crosschainforwarders/CrosschainForwarderArbitrum.sol'; -import {CrosschainForwarderMetis} from '../src/crosschainforwarders/CrosschainForwarderMetis.sol'; - -contract DeployPol is EthereumScript { - function run() external broadcast { - new CrosschainForwarderPolygon(); - } -} - -contract DeployOpt is EthereumScript { - function run() external broadcast { - new CrosschainForwarderOptimism(); - } -} - -contract DeployArb is EthereumScript { - function run() external broadcast { - new CrosschainForwarderArbitrum(); - } -} - -contract DeployMet is EthereumScript { - function run() external broadcast { - new CrosschainForwarderMetis(); - } -} diff --git a/src/GovHelpers.sol b/src/GovHelpers.sol index 421a91437..c2e2f2e05 100644 --- a/src/GovHelpers.sol +++ b/src/GovHelpers.sol @@ -3,9 +3,8 @@ pragma solidity >=0.7.5 <0.9.0; pragma abicoder v2; import {Vm} from 'forge-std/Vm.sol'; -import {console2} from 'forge-std/console2.sol'; -import {IpfsUtils} from './IpfsUtils.sol'; -import {AaveGovernanceV2, IAaveGovernanceV2, IExecutorWithTimelock} from 'aave-address-book/AaveGovernanceV2.sol'; +import {AaveGovernanceV2} from 'aave-address-book/AaveGovernanceV2.sol'; +import {IExecutorWithTimelock} from 'aave-address-book/common/IExecutorWithTimelock.sol'; import {IPoolAddressesProvider} from 'aave-address-book/AaveV3.sol'; import {AaveV3Avalanche} from 'aave-address-book/AaveV3Avalanche.sol'; import {AaveV3Harmony} from 'aave-address-book/AaveV3Harmony.sol'; @@ -23,14 +22,6 @@ interface CommonExecutor { function execute(uint256 actionsSetId) external payable; } -interface IProposalValidator { - /** - * @dev Get voting duration constant value - * @return the voting duration value in seconds - **/ - function VOTING_DURATION() external view returns (uint256); -} - library GovHelpers { error ExecutorNotFound(); error LongBytesNotSupportedYet(); @@ -43,10 +34,6 @@ library GovHelpers { bool withDelegatecall; } - function ipfsHashFile(Vm vm, string memory filePath) internal returns (bytes32) { - return IpfsUtils.ipfsHashFile(vm, filePath, false); - } - function buildMainnet(address payloadAddress) internal pure returns (Payload memory) { require(payloadAddress != address(0), 'NON_ZERO_TARGET'); require( @@ -123,128 +110,6 @@ library GovHelpers { }); } - function createProposal(Payload[] memory payloads, bytes32 ipfsHash) internal returns (uint256) { - return _createProposal(AaveGovernanceV2.SHORT_EXECUTOR, payloads, ipfsHash, false); - } - - function createProposal( - Payload[] memory payloads, - bytes32 ipfsHash, - bool emitLog - ) internal returns (uint256) { - return _createProposal(AaveGovernanceV2.SHORT_EXECUTOR, payloads, ipfsHash, emitLog); - } - - function createProposal( - Payload[] memory payloads, - bytes32 ipfsHash, - address executor - ) internal returns (uint256) { - return _createProposal(executor, payloads, ipfsHash, false); - } - - function createProposal( - Payload[] memory payloads, - bytes32 ipfsHash, - bool emitLog, - address executor - ) internal returns (uint256) { - return _createProposal(executor, payloads, ipfsHash, emitLog); - } - - function _createProposal( - address executor, - Payload[] memory payloads, - bytes32 ipfsHash, - bool emitLog - ) private returns (uint256) { - require(block.chainid == ChainIds.MAINNET, 'MAINNET_ONLY'); - require(payloads.length != 0, 'MINIMUM_ONE_PAYLOAD'); - require(ipfsHash != bytes32(0), 'NON_ZERO_IPFS_HASH'); - - address[] memory targets = new address[](payloads.length); - uint256[] memory values = new uint256[](payloads.length); - string[] memory signatures = new string[](payloads.length); - bytes[] memory calldatas = new bytes[](payloads.length); - bool[] memory withDelegatecalls = new bool[](payloads.length); - for (uint256 i = 0; i < payloads.length; i++) { - require(payloads[i].target != address(0), 'NON_ZERO_TARGET'); - targets[i] = payloads[i].target; - signatures[i] = payloads[i].signature; - calldatas[i] = payloads[i].callData; - values[i] = payloads[i].value; - withDelegatecalls[i] = payloads[i].withDelegatecall; - } - - if (emitLog) { - console2.logBytes( - abi.encodeWithSelector( - AaveGovernanceV2.GOV.create.selector, - IExecutorWithTimelock(executor), - targets, - values, - signatures, - calldatas, - withDelegatecalls, - ipfsHash - ) - ); - } - - return - AaveGovernanceV2.GOV.create( - IExecutorWithTimelock(executor), - targets, - values, - signatures, - calldatas, - withDelegatecalls, - ipfsHash - ); - } - - /** - * @dev Impersonate the ecosystem reserve and creates the proposal. - */ - function createTestProposal( - Vm vm, - Payload[] memory payloads, - address executor - ) internal returns (uint256) { - vm.deal(MiscEthereum.ECOSYSTEM_RESERVE, 1 ether); - vm.startPrank(MiscEthereum.ECOSYSTEM_RESERVE); - uint256 proposalId = _createProposal(executor, payloads, bytes32('test'), false); - vm.stopPrank(); - return proposalId; - } - - function passVoteAndExecute(Vm vm, uint256 proposalId) internal { - passVoteAndQueue(vm, proposalId); - uint256 executionTime = AaveGovernanceV2.GOV.getProposalById(proposalId).executionTime; - vm.warp(executionTime + 1); - AaveGovernanceV2.GOV.execute(proposalId); - } - - function passVoteAndQueue(Vm vm, uint256 proposalId) internal { - passVote(vm, proposalId); - AaveGovernanceV2.GOV.queue(proposalId); - } - - /** - * Alter storage slots so the proposal passes - */ - function passVote(Vm vm, uint256 proposalId) internal { - uint256 power = 5000000 ether; - vm.roll(block.number + 1); - vm.store( - address(AaveGovernanceV2.GOV), - bytes32(uint256(keccak256(abi.encode(proposalId, 0x4))) + 11), - bytes32(power) - ); - uint256 endBlock = AaveGovernanceV2.GOV.getProposalById(proposalId).endBlock; - vm.roll(endBlock + 1); - } - /** * @dev executes latest actionset on a l2 executor * @param vm Vm instance passed down from test @@ -370,169 +235,6 @@ library GovHelpers { return proposalCount; } - /** - * @notice Creates a proposal via storage overwrites - * @param vm vm - * @param params proposal - */ - function _queueProposalToL1ExecutorStorage( - Vm vm, - address l1Executor, - Payload[] memory params - ) internal returns (uint256) { - // struct Proposal { - // uint256 id; // 0 - // address creator; // 1 - // IExecutorWithTimelock executor; // 2 - // address[] targets; // 3 - // uint256[] values; // 4 - // string[] signatures; // 5 - // bytes[] calldatas; // 6 - // bool[] withDelegatecalls; // 7 - // uint256 startBlock; // 8 - // uint256 endBlock; // 9 - // uint256 executionTime; // 10 - // uint256 forVotes; // 11 - // uint256 againstVotes; // 12 - // bool executed; // 13 0-8 - // bool canceled; // 13 9-16 - // address strategy; // 13 16-176 - // bytes32 ipfsHash; // 14 - // mapping(address => Vote) votes; // 15 - // } - // count is stored in slot 5 - uint256 proposalCount = uint256(vm.load(address(AaveGovernanceV2.GOV), bytes32(uint256(3)))); - // bump counter by 1 - vm.store(address(AaveGovernanceV2.GOV), bytes32(uint256(3)), bytes32(proposalCount + 1)); - - // set storage array sizes - // proposals - uint256 proposalBaseSlot = StorageHelpers.getStorageSlotUintMapping(4, proposalCount); - // id - vm.store(address(AaveGovernanceV2.GOV), bytes32(proposalBaseSlot), bytes32(proposalCount)); - // creator - vm.store( - address(AaveGovernanceV2.GOV), - bytes32(proposalBaseSlot + 1), - bytes32(uint256(uint160(msg.sender))) - ); - // executor - vm.store( - address(AaveGovernanceV2.GOV), - bytes32(proposalBaseSlot + 2), - bytes32(uint256(uint160(l1Executor))) - ); - // targets - vm.store(address(AaveGovernanceV2.GOV), bytes32(proposalBaseSlot + 3), bytes32(params.length)); - // values - vm.store(address(AaveGovernanceV2.GOV), bytes32(proposalBaseSlot + 4), bytes32(params.length)); - // signatures - vm.store(address(AaveGovernanceV2.GOV), bytes32(proposalBaseSlot + 5), bytes32(params.length)); - // calldatas - vm.store(address(AaveGovernanceV2.GOV), bytes32(proposalBaseSlot + 6), bytes32(params.length)); - // withDelegateCalls - vm.store(address(AaveGovernanceV2.GOV), bytes32(proposalBaseSlot + 7), bytes32(params.length)); - // block math - uint256 dalay = AaveGovernanceV2.GOV.getVotingDelay(); // (blocks) delay in voting blocks before voting can happen - uint256 duration = IProposalValidator(l1Executor).VOTING_DURATION(); // (blocks) duration of the voting - uint256 executionTime = block.timestamp; - // @dev the block timings are not accurate, but enough to satisfy execution - // startBlock - vm.store( - address(AaveGovernanceV2.GOV), - bytes32(proposalBaseSlot + 8), - bytes32(block.number - (dalay + duration)) - ); - // endBlock - vm.store( - address(AaveGovernanceV2.GOV), - bytes32(proposalBaseSlot + 9), - bytes32(block.number - 1) - ); - // executionTime - vm.store(address(AaveGovernanceV2.GOV), bytes32(proposalBaseSlot + 10), bytes32(executionTime)); - // forVotes - vm.store( - address(AaveGovernanceV2.GOV), - bytes32(proposalBaseSlot + 11), - bytes32(uint256(15_000_000 ether)) // TODO: calculate needed amount - ); - // strategy - vm.store( - address(AaveGovernanceV2.GOV), - bytes32(proposalBaseSlot + 13), - bytes32(uint256(uint160(AaveGovernanceV2.GOV.getGovernanceStrategy())) << 16) - ); - // store actual values - for (uint256 i = 0; i < params.length; i++) { - bytes32 queueHash = keccak256( - abi.encode( - params[i].target, - 0, - params[i].signature, - params[i].callData, - executionTime, - true - ) - ); - // queue hash on executor - vm.store( - l1Executor, - bytes32( - StorageHelpers.getStorageSlotBytes32Mapping( - // the mapping slot is 3 on short and 7 on long - l1Executor == AaveGovernanceV2.SHORT_EXECUTOR ? 3 : 7, - queueHash - ) - ), - bytes32(uint256(1)) - ); - // targets - vm.store( - address(AaveGovernanceV2.GOV), - bytes32(StorageHelpers.arrLocation(proposalBaseSlot + 3, i, 1)), - bytes32(uint256(uint160(params[i].target))) - ); - // values - vm.store( - address(AaveGovernanceV2.GOV), - bytes32(StorageHelpers.arrLocation(proposalBaseSlot + 4, i, 1)), - bytes32(0) - ); - // signatures - if (bytes(params[i].signature).length > 31) revert LongBytesNotSupportedYet(); - vm.store( - address(AaveGovernanceV2.GOV), - bytes32(StorageHelpers.arrLocation(proposalBaseSlot + 5, i, 1)), - bytes32( - bytes.concat( - bytes31(bytes(params[i].signature)), - bytes1(uint8(bytes(params[i].signature).length * 2)) - ) - ) - ); - // calldatas - if (params[i].callData.length > 31) revert LongBytesNotSupportedYet(); - vm.store( - address(AaveGovernanceV2.GOV), - bytes32(StorageHelpers.arrLocation(proposalBaseSlot + 6, i, 1)), - bytes32( - bytes.concat( - bytes31(bytes(params[i].callData)), - bytes1(uint8(bytes(params[i].callData).length * 2)) - ) - ) - ); - // withDelegateCalls - vm.store( - address(AaveGovernanceV2.GOV), - bytes32(StorageHelpers.arrLocation(proposalBaseSlot + 7, i, 1)), - bytes32(uint256(1)) - ); - } - return proposalCount; - } - function _isKnownL2Executor(address executor) internal view returns (bool) { if (executor == AaveGovernanceV2.OPTIMISM_BRIDGE_EXECUTOR && block.chainid == ChainIds.OPTIMISM) return true; diff --git a/src/GovV3Helpers.sol b/src/GovV3Helpers.sol index acf11fa5c..94b090e1c 100644 --- a/src/GovV3Helpers.sol +++ b/src/GovV3Helpers.sol @@ -23,7 +23,6 @@ import {MiscEthereum} from 'aave-address-book/MiscEthereum.sol'; import {Address} from 'solidity-utils/contracts/oz-common/Address.sol'; import {StorageHelpers} from './StorageHelpers.sol'; import {ProxyHelpers} from './ProxyHelpers.sol'; -import {GovHelpers, IAaveGovernanceV2} from './GovHelpers.sol'; import {Create2Utils} from './ScriptUtils.sol'; interface IGovernance_V2_5 { @@ -588,37 +587,6 @@ library GovV3Helpers { GovernanceV3Ethereum.GOVERNANCE.executeProposal(proposalId); } - function build2_5Payload( - PayloadsControllerUtils.Payload memory payload - ) internal returns (GovHelpers.Payload memory) { - return - GovHelpers.Payload({ - target: address(GovernanceV3Ethereum.GOVERNANCE), - value: 0, - signature: 'forwardPayloadForExecution((uint256,uint8,address,uint40))', - callData: abi.encode(payload), - withDelegatecall: false - }); - } - - // temporarily patched create proposal for governance v2.5 - function createProposal2_5( - Vm vm, - PayloadsControllerUtils.Payload[] memory payloads, - bytes32 ipfsHash - ) internal returns (uint256) { - require(block.chainid == ChainIds.MAINNET, 'MAINNET_ONLY'); - require(payloads.length != 0, 'MINIMUM_ONE_PAYLOAD'); - require(ipfsHash != bytes32(0), 'NON_ZERO_IPFS_HASH'); - - generateProposalPreviewLink(vm, payloads, ipfsHash, address(0)); - GovHelpers.Payload[] memory gov2Payloads = new GovHelpers.Payload[](payloads.length); - for (uint256 i = 0; i < payloads.length; i++) { - gov2Payloads[i] = build2_5Payload(payloads[i]); - } - return GovHelpers.createProposal(gov2Payloads, ipfsHash, true); - } - /** * @dev creates a proposal with a single payload * @param vm Vm diff --git a/src/crosschainforwarders/CrosschainForwarderArbitrum.sol b/src/crosschainforwarders/CrosschainForwarderArbitrum.sol deleted file mode 100644 index 9c0aa56f2..000000000 --- a/src/crosschainforwarders/CrosschainForwarderArbitrum.sol +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {AaveGovernanceV2} from 'aave-address-book/AaveGovernanceV2.sol'; -import {AaveV3Arbitrum} from 'aave-address-book/AaveV3Arbitrum.sol'; -import {IInbox} from 'governance-crosschain-bridges/contracts/dependencies/arbitrum/interfaces/IInbox.sol'; -import {IL2BridgeExecutor} from 'governance-crosschain-bridges/contracts/interfaces/IL2BridgeExecutor.sol'; - -/** - * @title A generic executor for proposals targeting the arbitrum v3 pool - * @author BGD Labs - * @notice You can **only** use this executor when the arbitrum payload has a `execute()` signature without parameters - * @notice You can **only** use this executor when the arbitrum payload is expected to be executed via `DELEGATECALL` - * @notice This contract assumes to be called via AAVE Governance V2 - * @notice This contract will assume the SHORT_EXECUTOR will be topped up with enough funds to fund the short executor - * @dev This executor is a generic wrapper to be used with Arbitrum Inbox (https://developer.offchainlabs.com/arbos/l1-to-l2-messaging) - * It encodes a parameterless `execute()` with delegate calls and a specified target. - * This encoded abi is then send to the Inbox to be synced executed on the arbitrum network. - * Once synced the ARBITRUM_BRIDGE_EXECUTOR will queue the execution of the payload. - */ -contract CrosschainForwarderArbitrum { - IInbox public constant INBOX = IInbox(0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f); - address public constant ARBITRUM_BRIDGE_EXECUTOR = AaveGovernanceV2.ARBITRUM_BRIDGE_EXECUTOR; - address public constant ARBITRUM_GUARDIAN = 0xbbd9f90699c1FA0D7A65870D241DD1f1217c96Eb; - - // amount of gwei to overpay on basefee for fast submission - uint256 public constant BASE_FEE_MARGIN = 10 gwei; - - /** - * @dev calculateRetryableSubmissionFee on `0x00000000000000000000000000000000000000C8` for a queue call with 1 slot will yield a constant gasLimit of `429478` - * To account for some margin we rounded up to 450000 - */ - uint256 public constant L2_GAS_LIMIT = 450000; - - /** - * @dev There is currently no oracle on L1 exposing gasPrice of arbitrum. Therefore we overpay by assuming 1 gwei (10x of current price). - */ - uint256 public constant L2_MAX_FEE_PER_GAS = 1 gwei; - - /** - * @dev returns the amount of gas needed for submitting the ticket - * @param bytesLength the payload bytes length (usually 580) - * @return uint256 maxSubmissionFee needed on L2 with BASE_FEE_MARGIN - * @return uint256 estimated L2 redepmption fee - */ - function getRequiredGas(uint256 bytesLength) public view returns (uint256, uint256) { - return ( - INBOX.calculateRetryableSubmissionFee(bytesLength, block.basefee + BASE_FEE_MARGIN), - L2_GAS_LIMIT * L2_MAX_FEE_PER_GAS - ); - } - - /** - * @dev checks if the short executor is topped up with enough eth for proposal execution - * with current basefee - * @param bytesLength the payload bytes length (usually 580) - * @return bool indicating if the SHORT_EXECUTOR has sufficient funds - * @return uint256 the gas required for ticket creation and redemption - */ - function hasSufficientGasForExecution(uint256 bytesLength) public view returns (bool, uint256) { - (uint256 maxSubmission, uint256 maxRedemption) = getRequiredGas(bytesLength); - uint256 requiredGas = maxSubmission + maxRedemption; - return (AaveGovernanceV2.SHORT_EXECUTOR.balance >= requiredGas, requiredGas); - } - - /** - * @dev encodes the queue call which is forwarded to arbitrum - * @param l2PayloadContract the address of the arbitrum payload - */ - function getEncodedPayload(address l2PayloadContract) public pure returns (bytes memory) { - address[] memory targets = new address[](1); - targets[0] = l2PayloadContract; - uint256[] memory values = new uint256[](1); - values[0] = 0; - string[] memory signatures = new string[](1); - signatures[0] = 'execute()'; - bytes[] memory calldatas = new bytes[](1); - calldatas[0] = ''; - bool[] memory withDelegatecalls = new bool[](1); - withDelegatecalls[0] = true; - return - abi.encodeWithSelector( - IL2BridgeExecutor.queue.selector, - targets, - values, - signatures, - calldatas, - withDelegatecalls - ); - } - - /** - * @dev this function will be executed once the proposal passes the mainnet vote. - * @param l2PayloadContract the arbitrum contract containing the `execute()` signature. - */ - function execute(address l2PayloadContract) public { - bytes memory queue = getEncodedPayload(l2PayloadContract); - (uint256 maxSubmission, uint256 maxRedemption) = getRequiredGas(queue.length); - INBOX.unsafeCreateRetryableTicket{value: maxSubmission + maxRedemption}( - ARBITRUM_BRIDGE_EXECUTOR, - 0, // l2CallValue - maxSubmission, // maxSubmissionCost - address(ARBITRUM_BRIDGE_EXECUTOR), // excessFeeRefundAddress - address(ARBITRUM_GUARDIAN), // callValueRefundAddress - L2_GAS_LIMIT, // gasLimit - L2_MAX_FEE_PER_GAS, // maxFeePerGas - queue - ); - } -} diff --git a/src/crosschainforwarders/CrosschainForwarderMetis.sol b/src/crosschainforwarders/CrosschainForwarderMetis.sol deleted file mode 100644 index 965dcb139..000000000 --- a/src/crosschainforwarders/CrosschainForwarderMetis.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {AaveGovernanceV2} from 'aave-address-book/AaveGovernanceV2.sol'; -import {ICrossDomainMessenger} from 'governance-crosschain-bridges/contracts/dependencies/optimism/interfaces/ICrossDomainMessenger.sol'; -import {IL2BridgeExecutor} from 'governance-crosschain-bridges/contracts/interfaces/IL2BridgeExecutor.sol'; - -/** - * @title A generic executor for proposals targeting the metis v3 pool - * @author BGD Labs - * @notice You can **only** use this executor when the metis payload has a `execute()` signature without parameters - * @notice You can **only** use this executor when the metis payload is expected to be executed via `DELEGATECALL` - * @notice The L2CrossDomainMessenger can **only** queue an action on metis with up to a max gas which is specified in `MAX_GAS_LIMIT`. - * It encodes and sends via the L2CrossDomainMessenger a message to queue for execution an action on L2, in the Aave METIS_BRIDGE_EXECUTOR. - */ -contract CrosschainForwarderMetis { - /** - * @dev The L1 Cross Domain Messenger contract sends messages from L1 to L2, and relays messages - * from L2 onto L1. In this contract it's used by the governance SHORT_EXECUTOR to send the encoded L2 queuing over the bridge. - */ - address public constant L1_CROSS_DOMAIN_MESSENGER_ADDRESS = - 0x081D1101855bD523bA69A9794e0217F0DB6323ff; - - /** - * @dev The metis bridge executor is a L2 governance execution contract. - * This contract allows queuing of proposals by allow listed addresses (in this case the L1 short executor). - * https://andromeda-explorer.metis.io/address/0x8EC77963068474a45016938Deb95E603Ca82a029 - */ - address public constant METIS_BRIDGE_EXECUTOR = AaveGovernanceV2.METIS_BRIDGE_EXECUTOR; - - /** - * @dev The gas limit of the queue transaction by the L2CrossDomainMessenger on L2. - * The limit seems reasonable considering the queue transaction, as all gas limits are prepaid. - */ - uint32 public constant MAX_GAS_LIMIT = 5_000_000; - - /** - * @dev this function will be executed once the proposal passes the mainnet vote. - * @param l2PayloadContract the metis contract containing the `execute()` signature. - */ - function execute(address l2PayloadContract) public { - address[] memory targets = new address[](1); - targets[0] = l2PayloadContract; - uint256[] memory values = new uint256[](1); - values[0] = 0; - string[] memory signatures = new string[](1); - signatures[0] = 'execute()'; - bytes[] memory calldatas = new bytes[](1); - calldatas[0] = ''; - bool[] memory withDelegatecalls = new bool[](1); - withDelegatecalls[0] = true; - - bytes memory queue = abi.encodeWithSelector( - IL2BridgeExecutor.queue.selector, - targets, - values, - signatures, - calldatas, - withDelegatecalls - ); - ICrossDomainMessenger(L1_CROSS_DOMAIN_MESSENGER_ADDRESS).sendMessage( - METIS_BRIDGE_EXECUTOR, - queue, - MAX_GAS_LIMIT - ); - } -} diff --git a/src/crosschainforwarders/CrosschainForwarderOptimism.sol b/src/crosschainforwarders/CrosschainForwarderOptimism.sol deleted file mode 100644 index fca432e82..000000000 --- a/src/crosschainforwarders/CrosschainForwarderOptimism.sol +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {ICrossDomainMessenger} from 'governance-crosschain-bridges/contracts/dependencies/optimism/interfaces/ICrossDomainMessenger.sol'; -import {IL2BridgeExecutor} from 'governance-crosschain-bridges/contracts/interfaces/IL2BridgeExecutor.sol'; - -interface ICanonicalTransactionChain { - function enqueueL2GasPrepaid() external view returns (uint256); -} - -/** - * @title A generic executor for proposals targeting the optimism v3 pool - * @author BGD Labs - * @notice You can **only** use this executor when the optimism payload has a `execute()` signature without parameters - * @notice You can **only** use this executor when the optimism payload is expected to be executed via `DELEGATECALL` - * @notice You can **only** execute payloads on optimism with up to prepayed gas which is specified in `enqueueL2GasPrepaid` gas. - * Prepaid gas is the maximum gas covered by the bridge without additional payment. - * @dev This executor is a generic wrapper to be used with Optimism CrossDomainMessenger (https://etherscan.io/address/0x25ace71c97b33cc4729cf772ae268934f7ab5fa1) - * It encodes and sends via the L2CrossDomainMessenger a message to queue for execution an action on L2, in the Aave OPTIMISM_BRIDGE_EXECUTOR. - */ -contract CrosschainForwarderOptimism { - /** - * @dev The L1 Cross Domain Messenger contract sends messages from L1 to L2, and relays messages - * from L2 onto L1. In this contract it's used by the governance SHORT_EXECUTOR to send the encoded L2 queuing over the bridge. - */ - address public constant L1_CROSS_DOMAIN_MESSENGER_ADDRESS = - 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1; - - /** - * @dev The optimism bridge executor is a L2 governance execution contract. - * This contract allows queuing of proposals by allow listed addresses (in this case the L1 short executor). - * https://optimistic.etherscan.io/address/0x7d9103572bE58FfE99dc390E8246f02dcAe6f611 - */ - address public constant OPTIMISM_BRIDGE_EXECUTOR = 0x7d9103572bE58FfE99dc390E8246f02dcAe6f611; - - /** - * @dev The CTC contract is an append only log of transactions which must be applied to the rollup state. - * It also holds configurations like the currently prepayed amount of gas which is what this contract is utilizing. - * https://etherscan.io/address/0x5e4e65926ba27467555eb562121fac00d24e9dd2#code - */ - ICanonicalTransactionChain public constant CANONICAL_TRANSACTION_CHAIN = - ICanonicalTransactionChain(0x5E4e65926BA27467555EB562121fac00D24E9dD2); - - /** - * @dev this function will be executed once the proposal passes the mainnet vote. - * @param l2PayloadContract the optimism contract containing the `execute()` signature. - */ - function execute(address l2PayloadContract) public { - address[] memory targets = new address[](1); - targets[0] = l2PayloadContract; - uint256[] memory values = new uint256[](1); - values[0] = 0; - string[] memory signatures = new string[](1); - signatures[0] = 'execute()'; - bytes[] memory calldatas = new bytes[](1); - calldatas[0] = ''; - bool[] memory withDelegatecalls = new bool[](1); - withDelegatecalls[0] = true; - - bytes memory queue = abi.encodeWithSelector( - IL2BridgeExecutor.queue.selector, - targets, - values, - signatures, - calldatas, - withDelegatecalls - ); - ICrossDomainMessenger(L1_CROSS_DOMAIN_MESSENGER_ADDRESS).sendMessage( - OPTIMISM_BRIDGE_EXECUTOR, - queue, - uint32(CANONICAL_TRANSACTION_CHAIN.enqueueL2GasPrepaid()) - ); - } -} diff --git a/src/crosschainforwarders/CrosschainForwarderPolygon.sol b/src/crosschainforwarders/CrosschainForwarderPolygon.sol deleted file mode 100644 index 1ada02d6c..000000000 --- a/src/crosschainforwarders/CrosschainForwarderPolygon.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import {IFxStateSender} from 'governance-crosschain-bridges/contracts/dependencies/polygon/fxportal/FxRoot.sol'; - -/** - * @title A generic executor for proposals targeting the polygon v3 pool - * @author BGD Labs - * @notice You can **only** use this executor when the polygon payload has a `execute()` signature without parameters - * @notice You can **only** use this executor when the polygon payload is expected to be executed via `DELEGATECALL` - * @dev This executor is a generic wrapper to be used with FX bridges (https://github.com/fx-portal/contracts) - * It encodes a parameterless `execute()` with delegate calls and a specified target. - * This encoded abi is then send to the FX-root to be synced to the FX-child on the polygon network. - * Once synced the POLYGON_BRIDGE_EXECUTOR will queue the execution of the payload. - */ -contract CrosschainForwarderPolygon { - address public constant FX_ROOT_ADDRESS = 0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2; - address public constant POLYGON_BRIDGE_EXECUTOR = 0xdc9A35B16DB4e126cFeDC41322b3a36454B1F772; - - /** - * @dev this function will be executed once the proposal passes the mainnet vote. - * @param l2PayloadContract the polygon contract containing the `execute()` signature. - */ - function execute(address l2PayloadContract) public { - address[] memory targets = new address[](1); - targets[0] = l2PayloadContract; - uint256[] memory values = new uint256[](1); - values[0] = 0; - string[] memory signatures = new string[](1); - signatures[0] = 'execute()'; - bytes[] memory calldatas = new bytes[](1); - calldatas[0] = ''; - bool[] memory withDelegatecalls = new bool[](1); - withDelegatecalls[0] = true; - - bytes memory actions = abi.encode(targets, values, signatures, calldatas, withDelegatecalls); - IFxStateSender(FX_ROOT_ADDRESS).sendMessageToChild(POLYGON_BRIDGE_EXECUTOR, actions); - } -} diff --git a/src/crosschainforwarders/README.md b/src/crosschainforwarders/README.md deleted file mode 100644 index 7d5d866b6..000000000 --- a/src/crosschainforwarders/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# CrosschainForwarder - -## About - -To simplify the process of creating a cross-chain proposal this repository contains opinionated `CrosschainForwarder` contracts for `Polygon`, `Optimism`, `Metis` and `Arbitrum` abstracting away the complexity of bridging & cross-chain gas calculations. -All the forwarders follow the same pattern. They expect a payload to be deployed on L2 and to be executed with a parameterless `execute()` signature and via `DELEGATECALL`. - -![visualization](./bridge-listing.png) - -### Polygon - -For a proposal to be executed on Polygon it needs to pass a mainnet governance proposal that sends an encoded payload via `sendMessageToChild(address,bytes)` on [FX_ROOT](https://etherscan.io/address/0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2#code)(mainnet) to [FX_CHILD](https://polygonscan.com/address/0x8397259c983751DAf40400790063935a11afa28a#code)(Polygon). -Once the state is synced to `FX_CHILD` on Polygon network it will queue the payload on [POLYGON_BRIDGE_EXECUTOR](https://polygonscan.com/address/0xdc9A35B16DB4e126cFeDC41322b3a36454B1F772#code). - -### Optimism - -For a proposal to be executed on Optimism it needs to pass a mainnet governance proposal that sends an encoded payload via `sendMessage(address,bytes,uint32)` on [L1_CROSS_DOMAIN_MESSENGER](https://etherscan.io/address/0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1)(mainnet) to [L2_CROSS_DOMAIN_MESSENGER](https://optimistic.etherscan.io/address/0x4200000000000000000000000000000000000007#code)(Optimism). -Once the state is `L2_CROSS_DOMAIN_MESSENGER` on Optimism it will queue the payload on [OPTIMISM_BRIDGE_EXECUTOR](https://optimistic.etherscan.io/address/0x7d9103572bE58FfE99dc390E8246f02dcAe6f611). - -### Metis - -Similar to Optimism, for a proposal to be executed on Metis it needs to pass a mainnet governance proposal that sends an encoded payload via `sendMessage(address,bytes,uint32)` on [L1_CROSS_DOMAIN_MESSENGER](https://etherscan.io/address/0x081D1101855bD523bA69A9794e0217F0DB6323ff)(mainnet) to [L2_CROSS_DOMAIN_MESSENGER](https://andromeda-explorer.metis.io/address/0x4200000000000000000000000000000000000007)(Metis). -Once the state is `L2_CROSS_DOMAIN_MESSENGER` on Metis it will queue the payload on [METIS_BRIDGE_EXECUTOR](https://andromeda-explorer.metis.io/address/0x8EC77963068474a45016938Deb95E603Ca82a029). - -Caveat: Opposed to the other messenger like on Optimism, using the Metis messenger requires a whitelist by the Metis team. The [SHORT_EXECUTOR](https://etherscan.io/address/0xEE56e2B3D491590B5b31738cC34d5232F378a8D5) has been whitelisted to use the messenger. Also, the gas to queue the payload by the messenger has been hardcoded to 5 million, which seems reasonable considering the queue transaction. Unlike Optimism, the Metis messenger has no limit on gas, and everything is prepaid. - -### Arbitrum - -For a proposal to be executed on Arbitrum it needs to pass a mainnet governance proposal that sends an encoded payload via `unsafeCreateRetryableTicket{value: uint256}(address,uint256,uint256,address,address,uint256,uint256,bytes)` on [INBOX](https://etherscan.io/address/0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f)(mainnet). The Arbitrum bridge will then call the bridged calldata via the L2_ALIAS of the mainnet `msg.sender` (in this case is the aliased mainnet governance executor) which will queue the payload on [ARBITRUM_BRIDGE_EXECUTOR](https://arbiscan.io/address/0x7d9103572bE58FfE99dc390E8246f02dcAe6f611). - -Caveat: Opposed to the other bridges, Arbitrum inbox bridge requires you to supply some gas. -For simplicity the `CrosschainForwarderArbitrum` expects some eth to be available on the [SHORT_EXECUTOR](https://etherscan.io/address/0xEE56e2B3D491590B5b31738cC34d5232F378a8D5). -You can check if you need to top-up the SHORT_EXECUTOR by calling `getRequiredGas(580)` on the `CrosschainForwarderArbitrum`. - -## Deployed addresses - -### Forwarders - -- [CrosschainForwarderPolygon](https://etherscan.io/address/0x158a6bc04f0828318821bae797f50b0a1299d45b#code) -- [CrosschainForwarderOptimism](https://etherscan.io/address/0x5f5c02875a8e9b5a26fbd09040abcfdeb2aa6711#code) -- [CrosschainForwarderMetis](https://etherscan.io/address/0x2fE52eF191F0BE1D98459BdaD2F1d3160336C08f#code) -- [CrosschainForwarderArbitrum](https://etherscan.io/address/0x2e2B1F112C4D79A9D22464F0D345dE9b792705f1#code) - -## References - -- [PolygonBridge: FxRoot](https://etherscan.io/address/0xfe5e5d361b2ad62c541bab87c45a0b9b018389a2#code) -- [PolygonBridge: PolygonBridgeExecutor](https://polygonscan.com/address/0xdc9A35B16DB4e126cFeDC41322b3a36454B1F772#code) - -- [OptimismBridge: L1CrossDomainMessenger](https://etherscan.io/address/0x25ace71c97b33cc4729cf772ae268934f7ab5fa1#readProxyContract) -- [OptimismBridge: OptimismBridgeExecutor](https://optimistic.etherscan.io/address/0x7d9103572be58ffe99dc390e8246f02dcae6f611#code) - -- [MetisBridge: L1CrossDomainMessenger](https://etherscan.io/address/0x081D1101855bD523bA69A9794e0217F0DB6323ff#code) -- [MetisBridge: MetisBridgeExecutor](https://andromeda-explorer.metis.io/address/0x8EC77963068474a45016938Deb95E603Ca82a029/contracts#address-tabs) - -- [ArbitrumBridge: Inbox](https://etherscan.io/address/0x4dbd4fc535ac27206064b68ffcf827b0a60bab3f#code) -- [ArtitrumBridge: ArbitrumBridgeExecutor](https://arbiscan.io/address/0x7d9103572be58ffe99dc390e8246f02dcae6f611#code) - -- [aave crosschain-bridge repository](https://github.com/aave/governance-crosschain-bridges#polygon-governance-bridge) -- [first ever Polygon bridge proposal](https://github.com/pakim249CAL/Polygon-Asset-Deployment-Generic-Executor) diff --git a/src/crosschainforwarders/bridge-listing.png b/src/crosschainforwarders/bridge-listing.png deleted file mode 100644 index 2ffb59451..000000000 Binary files a/src/crosschainforwarders/bridge-listing.png and /dev/null differ diff --git a/tests/crosschainforwarders/ArbitrumCrossChainForwarderTest.t.sol b/tests/crosschainforwarders/ArbitrumCrossChainForwarderTest.t.sol deleted file mode 100644 index c6301ca72..000000000 --- a/tests/crosschainforwarders/ArbitrumCrossChainForwarderTest.t.sol +++ /dev/null @@ -1,151 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import 'forge-std/Test.sol'; -import {MiscEthereum} from 'aave-address-book/MiscEthereum.sol'; -import {AaveV3Arbitrum} from 'aave-address-book/AaveV3Arbitrum.sol'; -import {AaveGovernanceV2, IExecutorWithTimelock} from 'aave-address-book/AaveGovernanceV2.sol'; -import {AddressAliasHelper} from 'governance-crosschain-bridges/contracts/dependencies/arbitrum/AddressAliasHelper.sol'; -import {IInbox} from 'governance-crosschain-bridges/contracts/dependencies/arbitrum/interfaces/IInbox.sol'; -import {IL2BridgeExecutor} from 'governance-crosschain-bridges/contracts/interfaces/IL2BridgeExecutor.sol'; -import {GovHelpers} from '../../src/GovHelpers.sol'; -import {ProtocolV3TestBase, ReserveConfig, ReserveTokens, IERC20} from '../../src/ProtocolV3TestBase.sol'; -import {ProtocolV3TestBase, ReserveConfig} from '../../src/ProtocolV3TestBase.sol'; -import {CrosschainForwarderArbitrum} from '../../src/crosschainforwarders/CrosschainForwarderArbitrum.sol'; -import {PayloadWithEmit} from '../mocks/PayloadWithEmit.sol'; - -/** - * This test covers syncing between mainnet and arbitrum. - */ -contract ArbitrumCrossChainForwarderTest is ProtocolV3TestBase { - event TestEvent(); - - // the identifiers of the forks - uint256 mainnetFork; - uint256 arbitrumFork; - - PayloadWithEmit public payloadWithEmit; - - IInbox public constant INBOX = IInbox(0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f); - - address public constant ARBITRUM_BRIDGE_EXECUTOR = AaveGovernanceV2.ARBITRUM_BRIDGE_EXECUTOR; - - uint256 public constant MESSAGE_LENGTH = 580; - - CrosschainForwarderArbitrum public forwarder; - - function setUp() public { - mainnetFork = vm.createSelectFork(vm.rpcUrl('mainnet'), 16128510); - forwarder = new CrosschainForwarderArbitrum(); - arbitrumFork = vm.createSelectFork(vm.rpcUrl('arbitrum'), 76261612); - payloadWithEmit = new PayloadWithEmit(); - } - - // utility to transform memory to calldata so array range access is available - function _cutBytes(bytes calldata input) public pure returns (bytes calldata) { - return input[64:]; - } - - function testHasSufficientGas() public { - vm.selectFork(mainnetFork); - assertEq(AaveGovernanceV2.SHORT_EXECUTOR.balance, 0); - (bool hasEnoughGasBefore, ) = forwarder.hasSufficientGasForExecution(580); - assertEq(hasEnoughGasBefore, false); - deal(address(AaveGovernanceV2.SHORT_EXECUTOR), 0.001 ether); - (bool hasEnoughGasAfter, ) = forwarder.hasSufficientGasForExecution(580); - assertEq(hasEnoughGasAfter, true); - } - - function testgetGetMaxSubmissionCost() public { - vm.selectFork(mainnetFork); - (uint256 maxSubmission, ) = forwarder.getRequiredGas(580); - assertGt(maxSubmission, 0); - } - - function testProposalE2E() public { - // assumes the short exec will be topped up with some eth to pay for l2 fee - vm.selectFork(mainnetFork); - deal(address(AaveGovernanceV2.SHORT_EXECUTOR), 0.001 ether); - - // 1. create l1 proposal - vm.startPrank(MiscEthereum.ECOSYSTEM_RESERVE); - GovHelpers.Payload[] memory payloads = new GovHelpers.Payload[](1); - payloads[0] = GovHelpers.Payload({ - target: address(forwarder), - value: 0, - signature: 'execute(address)', - callData: abi.encode(address(payloadWithEmit)), - withDelegatecall: true - }); - - uint256 proposalId = GovHelpers.createProposal( - payloads, - 0xec9d2289ab7db9bfbf2b0f2dd41ccdc0a4003e9e0d09e40dee09095145c63fb5 - ); - vm.stopPrank(); - - // 2. execute proposal and record logs so we can extract the emitted StateSynced event - vm.recordLogs(); - bytes memory payload = forwarder.getEncodedPayload(address(payloadWithEmit)); - - (uint256 maxSubmission, ) = forwarder.getRequiredGas(580); - // check ticket is created correctly - vm.expectCall( - address(INBOX), - abi.encodeCall( - IInbox.unsafeCreateRetryableTicket, - ( - ARBITRUM_BRIDGE_EXECUTOR, - 0, - maxSubmission, - forwarder.ARBITRUM_BRIDGE_EXECUTOR(), - forwarder.ARBITRUM_GUARDIAN(), - forwarder.L2_GAS_LIMIT(), - forwarder.L2_MAX_FEE_PER_GAS(), - payload - ) - ) - ); - GovHelpers.passVoteAndExecute(vm, proposalId); - - // check events are emitted correctly - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(keccak256('InboxMessageDelivered(uint256,bytes)'), entries[3].topics[0]); - // uint256 messageId = uint256(entries[3].topics[1]); - ( - address to, - uint256 callvalue, - uint256 value, - uint256 maxSubmissionCost, - address excessFeeRefundAddress, - address callValueRefundAddress, - uint256 maxGas, - uint256 gasPriceBid, - uint256 length - ) = abi.decode( - this._cutBytes(entries[3].data), - (address, uint256, uint256, uint256, address, address, uint256, uint256, uint256) - ); - assertEq(callvalue, 0); - assertEq(value > 0, true); - assertEq(maxSubmissionCost > 0, true); - assertEq(to, ARBITRUM_BRIDGE_EXECUTOR); - assertEq(excessFeeRefundAddress, ARBITRUM_BRIDGE_EXECUTOR); - assertEq(callValueRefundAddress, forwarder.ARBITRUM_GUARDIAN()); - assertEq(maxGas, forwarder.L2_GAS_LIMIT()); - assertEq(gasPriceBid, forwarder.L2_MAX_FEE_PER_GAS()); - assertEq(length, 580); - - // 3. mock the queuing on l2 with the data emitted on InboxMessageDelivered - vm.selectFork(arbitrumFork); - vm.startPrank(AddressAliasHelper.applyL1ToL2Alias(AaveGovernanceV2.SHORT_EXECUTOR)); - - (bool success, ) = ARBITRUM_BRIDGE_EXECUTOR.call(payload); - assertEq(success, true); - vm.stopPrank(); - // 4. execute the proposal - vm.expectEmit(true, true, true, true); - emit TestEvent(); - GovHelpers.executeLatestActionSet(vm, ARBITRUM_BRIDGE_EXECUTOR); - } -} diff --git a/tests/crosschainforwarders/MetisCrossChainForwarderTest.t.sol b/tests/crosschainforwarders/MetisCrossChainForwarderTest.t.sol deleted file mode 100644 index 9b59fb8e2..000000000 --- a/tests/crosschainforwarders/MetisCrossChainForwarderTest.t.sol +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import 'forge-std/Test.sol'; -import {MiscEthereum} from 'aave-address-book/MiscEthereum.sol'; -import {AaveGovernanceV2} from 'aave-address-book/AaveGovernanceV2.sol'; -import {IL2CrossDomainMessenger} from 'governance-crosschain-bridges/contracts/dependencies/optimism/interfaces/IL2CrossDomainMessenger.sol'; -import {GovHelpers} from '../../src/GovHelpers.sol'; -import {ProtocolV3TestBase} from '../../src/ProtocolV3TestBase.sol'; -import {CrosschainForwarderMetis} from '../../src/crosschainforwarders/CrosschainForwarderMetis.sol'; -import {PayloadWithEmit} from '../mocks/PayloadWithEmit.sol'; - -/** - * This test covers syncing between mainnet and metis. - */ -contract MetisCrossChainForwarderTest is ProtocolV3TestBase { - event TestEvent(); - // the identifiers of the forks - uint256 mainnetFork; - uint256 metisFork; - - address public constant METIS_BRIDGE_EXECUTOR = AaveGovernanceV2.METIS_BRIDGE_EXECUTOR; - - IL2CrossDomainMessenger public OVM_L2_CROSS_DOMAIN_MESSENGER = - IL2CrossDomainMessenger(0x4200000000000000000000000000000000000007); - - PayloadWithEmit public payloadWithEmit; - - CrosschainForwarderMetis public forwarder; - - function setUp() public { - mainnetFork = vm.createSelectFork(vm.rpcUrl('mainnet'), 17093477); - forwarder = new CrosschainForwarderMetis(); - metisFork = vm.createSelectFork(vm.rpcUrl('metis'), 5428548); - payloadWithEmit = new PayloadWithEmit(); - } - - function testProposalE2E() public { - // 1. create l1 proposal - vm.selectFork(mainnetFork); - vm.startPrank(MiscEthereum.ECOSYSTEM_RESERVE); - GovHelpers.Payload[] memory payloads = new GovHelpers.Payload[](1); - payloads[0] = GovHelpers.Payload({ - target: address(forwarder), - value: 0, - signature: 'execute(address)', - callData: abi.encode(address(payloadWithEmit)), - withDelegatecall: true - }); - - uint256 proposalId = GovHelpers.createProposal(payloads, 'ipfs'); - vm.stopPrank(); - - // 2. execute proposal and record logs so we can extract the emitted StateSynced event - vm.recordLogs(); - GovHelpers.passVoteAndExecute(vm, proposalId); - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq( - keccak256('SentMessage(address,address,bytes,uint256,uint256,uint256)'), - entries[3].topics[0] - ); - assertEq(address(uint160(uint256(entries[3].topics[1]))), METIS_BRIDGE_EXECUTOR); - (address sender, bytes memory message, uint256 nonce) = abi.decode( - entries[3].data, - (address, bytes, uint256) - ); - - // 3. mock the receive on l2 with the data emitted on StateSynced - vm.selectFork(metisFork); - vm.startPrank(0x192E1101855bD523Ba69a9794e0217f0Db633510); // AddressAliasHelper.applyL1ToL2Alias on L1_CROSS_DOMAIN_MESSENGER_ADDRESS - OVM_L2_CROSS_DOMAIN_MESSENGER.relayMessage(METIS_BRIDGE_EXECUTOR, sender, message, nonce); - vm.stopPrank(); - - // 4. execute proposal on l2 - vm.expectEmit(true, true, true, true); - emit TestEvent(); - GovHelpers.executeLatestActionSet(vm, METIS_BRIDGE_EXECUTOR); - } -} diff --git a/tests/crosschainforwarders/OptimismCrossChainForwarderTest.t.sol b/tests/crosschainforwarders/OptimismCrossChainForwarderTest.t.sol deleted file mode 100644 index 982a70c33..000000000 --- a/tests/crosschainforwarders/OptimismCrossChainForwarderTest.t.sol +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import 'forge-std/Test.sol'; -import {MiscEthereum} from 'aave-address-book/MiscEthereum.sol'; -import {AaveV3Optimism} from 'aave-address-book/AaveV3Optimism.sol'; -import {AaveGovernanceV2, IExecutorWithTimelock} from 'aave-address-book/AaveGovernanceV2.sol'; -import {AddressAliasHelper} from 'governance-crosschain-bridges/contracts/dependencies/arbitrum/AddressAliasHelper.sol'; -import {IL2CrossDomainMessenger} from 'governance-crosschain-bridges/contracts/dependencies/optimism/interfaces/IL2CrossDomainMessenger.sol'; -import {GovHelpers} from '../../src/GovHelpers.sol'; -import {ProtocolV3TestBase, ReserveConfig, ReserveTokens, IERC20} from '../../src/ProtocolV3TestBase.sol'; -import {CrosschainForwarderOptimism} from '../../src/crosschainforwarders/CrosschainForwarderOptimism.sol'; -import {PayloadWithEmit} from '../mocks/PayloadWithEmit.sol'; - -/** - * This test covers syncing between mainnet and optimism. - */ -contract OptimismCrossChainForwarderTest is ProtocolV3TestBase { - event TestEvent(); - // the identifiers of the forks - uint256 mainnetFork; - uint256 optimismFork; - - address public constant OPTIMISM_BRIDGE_EXECUTOR = AaveGovernanceV2.OPTIMISM_BRIDGE_EXECUTOR; - - IL2CrossDomainMessenger public OVM_L2_CROSS_DOMAIN_MESSENGER = - IL2CrossDomainMessenger(0x4200000000000000000000000000000000000007); - - PayloadWithEmit public payloadWithEmit; - - CrosschainForwarderOptimism public forwarder; - - function setUp() public { - mainnetFork = vm.createSelectFork(vm.rpcUrl('mainnet'), 15783218); - forwarder = new CrosschainForwarderOptimism(); - optimismFork = vm.createSelectFork(vm.rpcUrl('optimism'), 30264427); - payloadWithEmit = new PayloadWithEmit(); - } - - function testProposalE2E() public { - // 1. create l1 proposal - vm.selectFork(mainnetFork); - vm.startPrank(MiscEthereum.ECOSYSTEM_RESERVE); - GovHelpers.Payload[] memory payloads = new GovHelpers.Payload[](1); - payloads[0] = GovHelpers.Payload({ - value: 0, - withDelegatecall: true, - target: address(forwarder), - signature: 'execute(address)', - callData: abi.encode(address(payloadWithEmit)) - }); - - uint256 proposalId = GovHelpers.createProposal( - payloads, - 0x7ecafb3b0b7e418336cccb0c82b3e25944011bf11e41f8dc541841da073fe4f1 - ); - vm.stopPrank(); - - // 2. execute proposal and record logs so we can extract the emitted StateSynced event - vm.recordLogs(); - GovHelpers.passVoteAndExecute(vm, proposalId); - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(keccak256('SentMessage(address,address,bytes,uint256,uint256)'), entries[3].topics[0]); - assertEq(address(uint160(uint256(entries[3].topics[1]))), OPTIMISM_BRIDGE_EXECUTOR); - (address sender, bytes memory message, uint256 nonce) = abi.decode( - entries[3].data, - (address, bytes, uint256) - ); - - // 3. mock the receive on l2 with the data emitted on StateSynced - vm.selectFork(optimismFork); - vm.startPrank(0x36BDE71C97B33Cc4729cf772aE268934f7AB70B2); // AddressAliasHelper.applyL1ToL2Alias on L1_CROSS_DOMAIN_MESSENGER_ADDRESS - OVM_L2_CROSS_DOMAIN_MESSENGER.relayMessage(OPTIMISM_BRIDGE_EXECUTOR, sender, message, nonce); - vm.stopPrank(); - - // 4. execute proposal on l2 - vm.expectEmit(true, true, true, true); - emit TestEvent(); - GovHelpers.executeLatestActionSet(vm, OPTIMISM_BRIDGE_EXECUTOR); - } -} diff --git a/tests/crosschainforwarders/PolygonCrossChainForwarderTest.t.sol b/tests/crosschainforwarders/PolygonCrossChainForwarderTest.t.sol deleted file mode 100644 index c0059134f..000000000 --- a/tests/crosschainforwarders/PolygonCrossChainForwarderTest.t.sol +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import 'forge-std/Test.sol'; -import {MiscEthereum} from 'aave-address-book/MiscEthereum.sol'; -import {AaveV3Polygon} from 'aave-address-book/AaveV3Polygon.sol'; -import {AaveGovernanceV2, IExecutorWithTimelock} from 'aave-address-book/AaveGovernanceV2.sol'; -import {IStateReceiver} from 'governance-crosschain-bridges/contracts/dependencies/polygon/fxportal/FxChild.sol'; -import {GovHelpers} from '../../src/GovHelpers.sol'; -import {ProtocolV3TestBase, ReserveConfig, ReserveTokens, IERC20} from '../../src/ProtocolV3TestBase.sol'; -import {CrosschainForwarderPolygon} from '../../src/crosschainforwarders/CrosschainForwarderPolygon.sol'; -import {PayloadWithEmit} from '../mocks/PayloadWithEmit.sol'; - -/** - * This test covers syncing between mainnet and polygon. - */ -contract PolygonCrossChainForwarderTest is ProtocolV3TestBase { - event TestEvent(); - // the identifiers of the forks - uint256 mainnetFork; - uint256 polygonFork; - - address public constant BRIDGE_ADMIN = 0x0000000000000000000000000000000000001001; - - address public constant FX_CHILD_ADDRESS = 0x8397259c983751DAf40400790063935a11afa28a; - - address public constant POLYGON_BRIDGE_EXECUTOR = AaveGovernanceV2.POLYGON_BRIDGE_EXECUTOR; - - PayloadWithEmit public payloadWithEmit; - - CrosschainForwarderPolygon public forwarder; - - function setUp() public { - mainnetFork = vm.createSelectFork(vm.rpcUrl('mainnet'), 15275388); - forwarder = new CrosschainForwarderPolygon(); - polygonFork = vm.createSelectFork(vm.rpcUrl('polygon'), 31507646); - payloadWithEmit = new PayloadWithEmit(); - } - - // utility to transform memory to calldata so array range access is available - function _cutBytes(bytes calldata input) public pure returns (bytes calldata) { - return input[64:]; - } - - function testProposalE2E() public { - // 1. create l1 proposal - vm.selectFork(mainnetFork); - vm.startPrank(MiscEthereum.ECOSYSTEM_RESERVE); - GovHelpers.Payload[] memory payloads = new GovHelpers.Payload[](1); - payloads[0] = GovHelpers.Payload({ - value: 0, - withDelegatecall: true, - target: address(forwarder), - signature: 'execute(address)', - callData: abi.encode(address(payloadWithEmit)) - }); - - uint256 proposalId = GovHelpers.createProposal( - payloads, - 0xf6e50d5a3f824f5ab4ffa15fb79f4fa1871b8bf7af9e9b32c1aaaa9ea633006d - ); - vm.stopPrank(); - - // 2. execute proposal and record logs so we can extract the emitted StateSynced event - vm.recordLogs(); - GovHelpers.passVoteAndExecute(vm, proposalId); - - Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(keccak256('StateSynced(uint256,address,bytes)'), entries[2].topics[0]); - assertEq(address(uint160(uint256(entries[2].topics[2]))), FX_CHILD_ADDRESS); - - // 3. mock the receive on l2 with the data emitted on StateSynced - vm.selectFork(polygonFork); - vm.startPrank(BRIDGE_ADMIN); - IStateReceiver(FX_CHILD_ADDRESS).onStateReceive( - uint256(entries[2].topics[1]), - this._cutBytes(entries[2].data) - ); - vm.stopPrank(); - - // 4. Forward time & execute proposal - vm.expectEmit(true, true, true, true); - emit TestEvent(); - GovHelpers.executeLatestActionSet(vm, POLYGON_BRIDGE_EXECUTOR); - } -} diff --git a/tests/v2-config-engine/V2RateStrategyFactory.t.sol b/tests/v2-config-engine/V2RateStrategyFactory.t.sol index b70342b0c..a3f8cd0e1 100644 --- a/tests/v2-config-engine/V2RateStrategyFactory.t.sol +++ b/tests/v2-config-engine/V2RateStrategyFactory.t.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {AaveV2Ethereum} from 'aave-address-book/AaveAddressBook.sol'; -import {AaveV2EthereumAssets} from 'aave-address-book/AaveV2Ethereum.sol'; +import {AaveV2Ethereum, AaveV2EthereumAssets} from 'aave-address-book/AaveV2Ethereum.sol'; import {IDefaultInterestRateStrategy} from 'aave-address-book/AaveV2.sol'; import {V2RateStrategyFactory, IV2RateStrategyFactory} from '../../src/v2-config-engine/V2RateStrategyFactory.sol'; import '../../src/ProtocolV2TestBase.sol';