wormhole/ethereum/forge-test/Governance.t.sol

1254 lines
45 KiB
Solidity

// test/Messages.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "../contracts/Implementation.sol";
import "../contracts/Setup.sol";
import "../contracts/Wormhole.sol";
import "forge-std/Test.sol";
import "forge-test/rv-helpers/TestUtils.sol";
import "forge-test/rv-helpers/MyImplementation.sol";
import "forge-test/rv-helpers/IMyWormhole.sol";
contract TestGovernance is TestUtils {
uint16 constant CHAINID = 2;
uint256 constant EVMCHAINID = 1;
bytes32 constant MODULE = 0x00000000000000000000000000000000000000000000000000000000436f7265;
bytes32 constant governanceContract = 0x0000000000000000000000000000000000000000000000000000000000000004;
bytes32 constant CHAINID_SLOT = bytes32(uint256(0));
bytes32 constant GUARDIANSETS_SLOT = bytes32(uint256(2));
bytes32 constant GUARDIANSETINDEX_SLOT = bytes32(uint256(3));
bytes32 constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
bytes32 constant CONSUMED_ACTIONS_SLOT = bytes32(uint256(5));
bytes32 constant INIT_IMPLEMENTATION_SLOT = bytes32(uint256(6));
bytes32 constant MESSAGEFEE_SLOT = bytes32(uint256(7));
bytes32 constant EVMCHAINID_SLOT = bytes32(uint256(8));
Wormhole proxy;
Implementation impl;
Setup setup;
Setup proxiedSetup;
IMyWormhole proxied;
uint256 constant testGuardian = 93941733246223705020089879371323733820373732307041878556247502674739205313440;
event ContractUpgraded(address indexed oldContract, address indexed newContract);
function setUp() public {
// Deploy setup
setup = new Setup();
// Deploy implementation contract
impl = new Implementation();
// Deploy proxy
proxy = new Wormhole(address(setup), bytes(""));
address[] memory keys = new address[](1);
keys[0] = 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe; // vm.addr(testGuardian)
//proxied setup
proxiedSetup = Setup(address(proxy));
vm.chainId(1);
proxiedSetup.setup({
implementation: address(impl),
initialGuardians: keys,
chainId: CHAINID,
governanceChainId: 1,
governanceContract: governanceContract,
evmChainId: EVMCHAINID
});
proxied = IMyWormhole(address(proxy));
}
function testSubmitContractUpgrade(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel)
public
unchangedStorage(address(proxied), storageSlot)
{
MyImplementation newImpl = new MyImplementation(EVMCHAINID, CHAINID);
vm.assume(storageSlot != IMPLEMENTATION_SLOT);
vm.assume(storageSlot != hashedLocation(address(newImpl), INIT_IMPLEMENTATION_SLOT));
bytes memory payload = payloadSubmitContract(MODULE, CHAINID, address(newImpl));
(bytes memory _vm, bytes32 hash) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.assume(storageSlot != hashedLocation(hash, CONSUMED_ACTIONS_SLOT));
proxied.submitContractUpgrade(_vm);
assertEq(address(newImpl), address(proxied.getImplementation()));
assertEq(true, proxied.isInitialized(address(newImpl)));
assertEq(true, proxied.governanceActionIsConsumed(hash));
}
function testSubmitContractUpgrade_Emit(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel)
public
unchangedStorage(address(proxied), storageSlot)
{
MyImplementation newImpl = new MyImplementation(EVMCHAINID, CHAINID);
vm.assume(storageSlot != IMPLEMENTATION_SLOT);
vm.assume(storageSlot != hashedLocation(address(newImpl), INIT_IMPLEMENTATION_SLOT));
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitContract(MODULE, CHAINID, address(newImpl));
(bytes memory _vm, bytes32 hash) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.assume(storageSlot != hashedLocation(hash, CONSUMED_ACTIONS_SLOT));
vm.expectEmit(true,true,true,true);
emit ContractUpgraded(address(impl), address(newImpl));
proxied.submitContractUpgrade(_vm);
}
function testInitialize_after_upgrade_revert(bytes32 storageSlot, address alice)
public
unchangedStorage(address(proxied), storageSlot)
{
Implementation newImpl = new Implementation();
vm.assume(storageSlot != IMPLEMENTATION_SLOT);
vm.assume(storageSlot != hashedLocation(address(newImpl), INIT_IMPLEMENTATION_SLOT));
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitContract(MODULE, 2, address(newImpl));
(bytes memory _vm, bytes32 hash) = validVm(0, 0, 0, 1, governanceContract, 0, 0, payload, testGuardian);
vm.assume(storageSlot != hashedLocation(hash, CONSUMED_ACTIONS_SLOT));
proxied.submitContractUpgrade(_vm);
vm.prank(alice);
vm.expectRevert("already initialized");
proxied.initialize();
}
function testSubmitContractUpgrade_Revert_InvalidFork(
bytes32 storageSlot,
uint64 evmChainId,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(evmChainId != EVMCHAINID);
vm.chainId(evmChainId);
MyImplementation newImpl = new MyImplementation(evmChainId, CHAINID);
bytes memory payload = payloadSubmitContract(MODULE, CHAINID, address(newImpl));
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("invalid fork");
proxied.submitContractUpgrade(_vm);
}
function testSubmitContractUpgrade_Revert_InvalidModule(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
bytes32 module)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(module != MODULE);
vm.chainId(EVMCHAINID);
MyImplementation newImpl = new MyImplementation(EVMCHAINID, CHAINID);
bytes memory payload = payloadSubmitContract(module, CHAINID, address(newImpl));
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("Invalid Module");
proxied.submitContractUpgrade(_vm);
}
function testSubmitContractUpgrade_Revert_InvalidChain(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint16 chainId)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(chainId != CHAINID);
vm.chainId(EVMCHAINID);
MyImplementation newImpl = new MyImplementation(EVMCHAINID, CHAINID);
bytes memory payload = payloadSubmitContract(MODULE, chainId, address(newImpl));
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("Invalid Chain");
proxied.submitContractUpgrade(_vm);
}
function testSubmitContractUpgrade_Revert_InvalidGuardianSetIndex(
bytes32 storageSlot,
uint32 guardianSetIndex,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(guardianSetIndex != 0);
vm.chainId(EVMCHAINID);
MyImplementation newImpl = new MyImplementation(EVMCHAINID, CHAINID);
bytes memory payload = payloadSubmitContract(MODULE, CHAINID, address(newImpl));
(bytes memory _vm, ) = validVm(
guardianSetIndex, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
// Since the current version of the test uses only one guardian set,
// in practice only the 'else' branch will be taken
if (guardianSetIndex < proxied.getCurrentGuardianSetIndex()) {
vm.expectRevert("not signed by current guardian set");
} else {
vm.expectRevert("invalid guardian set");
}
proxied.submitContractUpgrade(_vm);
}
function testSubmitContractUpgrade_Revert_WrongGovernanceChain(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint16 emitterChainId,
uint64 sequence,
uint8 consistencyLevel)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(emitterChainId != 1);
vm.chainId(EVMCHAINID);
MyImplementation newImpl = new MyImplementation(EVMCHAINID, CHAINID);
bytes memory payload = payloadSubmitContract(MODULE, CHAINID, address(newImpl));
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, emitterChainId, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("wrong governance chain");
proxied.submitContractUpgrade(_vm);
}
function testSubmitContractUpgrade_Revert_WrongGovernanceContract(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
bytes32 emitterAddress,
uint64 sequence,
uint8 consistencyLevel)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(emitterAddress != governanceContract);
vm.chainId(EVMCHAINID);
MyImplementation newImpl = new MyImplementation(EVMCHAINID, CHAINID);
bytes memory payload = payloadSubmitContract(MODULE, CHAINID, address(newImpl));
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, emitterAddress, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("wrong governance contract");
proxied.submitContractUpgrade(_vm);
}
function testSubmitContractUpgrade_Revert_ReplayAttack(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.chainId(EVMCHAINID);
MyImplementation newImpl = new MyImplementation(EVMCHAINID, CHAINID);
bytes memory payload = payloadSubmitContract(MODULE, CHAINID, address(newImpl));
(bytes memory _vm, bytes32 hash) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.assume(storageSlot != hashedLocation(hash, CONSUMED_ACTIONS_SLOT));
proxied.submitContractUpgrade(_vm);
vm.expectRevert("governance action already consumed");
proxied.submitContractUpgrade(_vm);
}
function testSubmitSetMessageFee(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint256 newMessageFee)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(storageSlot != MESSAGEFEE_SLOT);
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitMessageFee(MODULE, CHAINID, newMessageFee);
(bytes memory _vm, bytes32 hash) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.assume(storageSlot != hashedLocation(hash, CONSUMED_ACTIONS_SLOT));
proxied.submitSetMessageFee(_vm);
assertEq(newMessageFee, proxied.messageFee());
assertEq(true, proxied.governanceActionIsConsumed(hash));
}
function testSubmitSetMessageFee_Revert_InvalidModule(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
bytes32 module,
uint256 newMessageFee)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(module != MODULE);
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitMessageFee(module, CHAINID, newMessageFee);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("Invalid Module");
proxied.submitSetMessageFee(_vm);
}
function testSubmitSetMessageFee_Revert_InvalidChain(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint16 chainId,
uint256 newMessageFee)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(chainId != CHAINID);
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitMessageFee(MODULE, chainId, newMessageFee);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("Invalid Chain");
proxied.submitSetMessageFee(_vm);
}
function testSubmitSetMessageFee_Revert_InvalidEvmChain(
bytes32 storageSlot,
uint64 evmChainId,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint256 newMessageFee)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(evmChainId != EVMCHAINID);
vm.chainId(evmChainId);
bytes memory payload = payloadSubmitMessageFee(MODULE, CHAINID, newMessageFee);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("Invalid Chain");
proxied.submitSetMessageFee(_vm);
}
function testSubmitSetMessageFee_Revert_InvalidGuardianSetIndex(
bytes32 storageSlot,
uint32 guardianSetIndex,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint256 newMessageFee)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(guardianSetIndex != 0);
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitMessageFee(MODULE, CHAINID, newMessageFee);
(bytes memory _vm, ) = validVm(
guardianSetIndex, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
// Since the current version of the test uses only one guardian set,
// in practice only the 'else' branch will be taken
if (guardianSetIndex < proxied.getCurrentGuardianSetIndex()) {
vm.expectRevert("not signed by current guardian set");
} else {
vm.expectRevert("invalid guardian set");
}
proxied.submitSetMessageFee(_vm);
}
function testSubmitSetMessageFee_Revert_WrongGovernanceChain(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint16 emitterChainId,
uint64 sequence,
uint8 consistencyLevel,
uint256 newMessageFee)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(emitterChainId != 1);
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitMessageFee(MODULE, CHAINID, newMessageFee);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, emitterChainId, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("wrong governance chain");
proxied.submitSetMessageFee(_vm);
}
function testSubmitSetMessageFee_Revert_WrongGovernanceContract(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
bytes32 emitterAddress,
uint64 sequence,
uint8 consistencyLevel,
uint256 newMessageFee)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(emitterAddress != governanceContract);
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitMessageFee(MODULE, CHAINID, newMessageFee);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, emitterAddress, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("wrong governance contract");
proxied.submitSetMessageFee(_vm);
}
function testSubmitSetMessageFee_Revert_ReplayAttack(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint256 newMessageFee)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(storageSlot != MESSAGEFEE_SLOT);
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitMessageFee(MODULE, CHAINID, newMessageFee);
(bytes memory _vm, bytes32 hash) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.assume(storageSlot != hashedLocation(hash, CONSUMED_ACTIONS_SLOT));
proxied.submitSetMessageFee(_vm);
vm.expectRevert("governance action already consumed");
proxied.submitSetMessageFee(_vm);
}
//Make a similar test but with chainId = 0
function testSubmitNewGuardianSet(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
address[] memory newGuardianSet)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(storageSlot != hashedLocationOffset(0, GUARDIANSETS_SLOT, 1));
// New GuardianSet array length should be initialized from zero to non-zero
vm.assume(storageSlot != hashedLocationOffset(1, GUARDIANSETS_SLOT, 0));
vm.assume(storageSlot != GUARDIANSETINDEX_SLOT);
vm.assume(0 < newGuardianSet.length);
vm.assume(newGuardianSet.length < 20);
for(uint8 i = 0; i < newGuardianSet.length; i++) {
vm.assume(newGuardianSet[i] != address(0));
// New GuardianSet key array elements should be initialized from zero to non-zero
vm.assume(storageSlot != arrayElementLocation(hashedLocationOffset(1, GUARDIANSETS_SLOT, 0), i));
}
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitNewGuardianSet(MODULE, CHAINID, 1, newGuardianSet);
(bytes memory _vm, bytes32 hash) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.assume(storageSlot != hashedLocation(hash, CONSUMED_ACTIONS_SLOT));
proxied.submitNewGuardianSet(_vm);
assertEq(true, proxied.governanceActionIsConsumed(hash));
assertEq(uint32(block.timestamp) + 86400, proxied.getGuardianSet(0).expirationTime);
assertEq(newGuardianSet, proxied.getGuardianSet(1).keys);
assertEq(1, proxied.getCurrentGuardianSetIndex());
}
function testSubmitNewGuardianSet_Revert_InvalidModule(
bytes32 storageSlot,
uint64 evmChainId,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
bytes32 module,
uint16 chainId,
address[] memory newGuardianSet)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(module != MODULE);
vm.assume(chainId == 0 || (chainId == CHAINID && evmChainId == EVMCHAINID));
vm.assume(newGuardianSet.length < 20);
vm.chainId(evmChainId);
bytes memory payload = payloadSubmitNewGuardianSet(module,chainId, 1, newGuardianSet);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("invalid Module");
proxied.submitNewGuardianSet(_vm);
}
function testSubmitNewGuardianSet_Revert_InvalidChain(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint16 chainId,
address[] memory newGuardianSet)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(chainId != CHAINID && chainId != 0);
vm.assume(newGuardianSet.length < 20);
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitNewGuardianSet(MODULE, chainId, 1, newGuardianSet);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("invalid Chain");
proxied.submitNewGuardianSet(_vm);
}
function testSubmitNewGuardianSet_Revert_InvalidEvmChain(
bytes32 storageSlot,
uint64 evmChainId,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
address[] memory newGuardianSet)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(evmChainId != EVMCHAINID);
vm.assume(newGuardianSet.length < 20);
vm.chainId(evmChainId);
bytes memory payload = payloadSubmitNewGuardianSet(MODULE, CHAINID, 1, newGuardianSet);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("invalid Chain");
proxied.submitNewGuardianSet(_vm);
}
function testSubmitNewGuardianSet_Revert_GuardianSetEmpty(
bytes32 storageSlot,
uint64 evmChainId,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint16 chainId)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(chainId == 0 || (chainId == CHAINID && evmChainId == EVMCHAINID));
vm.chainId(evmChainId);
address[] memory newGuardianSet = new address[](0); // Empty guardian set
bytes memory payload = payloadSubmitNewGuardianSet(MODULE, chainId, 1, newGuardianSet);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("new guardian set is empty");
proxied.submitNewGuardianSet(_vm);
}
function testSubmitNewGuardianSet_Revert_WrongIndex(
bytes32 storageSlot,
uint64 evmChainId,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint16 chainId,
uint32 newGuardianSetIndex,
address[] memory newGuardianSet)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(newGuardianSetIndex != 1);
vm.assume(chainId == 0 || (chainId == CHAINID && evmChainId == EVMCHAINID));
vm.assume(0 < newGuardianSet.length);
vm.assume(newGuardianSet.length < 20);
vm.chainId(evmChainId);
bytes memory payload = payloadSubmitNewGuardianSet(MODULE, chainId, newGuardianSetIndex, newGuardianSet);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("index must increase in steps of 1");
proxied.submitNewGuardianSet(_vm);
}
function testSubmitNewGuardianSet_Revert_InvalidGuardianSetIndex(
bytes32 storageSlot,
uint32 guardianSetIndex,
uint64 evmChainId,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint16 chainId,
address[] memory newGuardianSet)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(guardianSetIndex != 0);
vm.assume(chainId == 0 || (chainId == CHAINID && evmChainId == EVMCHAINID));
vm.assume(0 < newGuardianSet.length);
vm.assume(newGuardianSet.length < 20);
vm.chainId(evmChainId);
bytes memory payload = payloadSubmitNewGuardianSet(MODULE, chainId, 1, newGuardianSet);
(bytes memory _vm, ) = validVm(
guardianSetIndex, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
// Since the current version of the test uses only one guardian set,
// in practice only the 'else' branch will be taken
if (guardianSetIndex < proxied.getCurrentGuardianSetIndex()) {
vm.expectRevert("not signed by current guardian set");
} else {
vm.expectRevert("invalid guardian set");
}
proxied.submitNewGuardianSet(_vm);
}
function testSubmitNewGuardianSet_Revert_WrongGovernanceChain(
bytes32 storageSlot,
uint64 evmChainId,
uint32 timestamp,
uint32 nonce,
uint16 emitterChainId,
uint64 sequence,
uint8 consistencyLevel,
uint16 chainId,
address[] memory newGuardianSet)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(emitterChainId != 1);
vm.assume(chainId == 0 || (chainId == CHAINID && evmChainId == EVMCHAINID));
vm.assume(0 < newGuardianSet.length);
vm.assume(newGuardianSet.length < 20);
vm.chainId(evmChainId);
bytes memory payload = payloadSubmitNewGuardianSet(MODULE, chainId, 1, newGuardianSet);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, emitterChainId, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("wrong governance chain");
proxied.submitNewGuardianSet(_vm);
}
function testSubmitNewGuardianSet_Revert_WrongGovernanceContract(
bytes32 storageSlot,
uint64 evmChainId,
uint32 timestamp,
uint32 nonce,
bytes32 emitterAddress,
uint64 sequence,
uint8 consistencyLevel,
uint16 chainId,
address[] memory newGuardianSet)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(emitterAddress != governanceContract);
vm.assume(chainId == 0 || (chainId == CHAINID && evmChainId == EVMCHAINID));
vm.assume(0 < newGuardianSet.length);
vm.assume(newGuardianSet.length < 20);
vm.chainId(evmChainId);
bytes memory payload = payloadSubmitNewGuardianSet(MODULE, chainId, 1, newGuardianSet);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, emitterAddress, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("wrong governance contract");
proxied.submitNewGuardianSet(_vm);
}
function testSubmitNewGuardianSet_Revert_ReplayAttack(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
address[] memory newGuardianSet)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(storageSlot != hashedLocationOffset(0, GUARDIANSETS_SLOT, 1));
// New GuardianSet array length should be initialized from zero to non-zero
vm.assume(storageSlot != hashedLocationOffset(1, GUARDIANSETS_SLOT, 0));
vm.assume(storageSlot != GUARDIANSETINDEX_SLOT);
vm.assume(0 < newGuardianSet.length);
vm.assume(newGuardianSet.length < 20);
for(uint8 i = 0; i < newGuardianSet.length; i++) {
vm.assume(newGuardianSet[i] != address(0));
// New GuardianSet key array elements should be initialized from zero to non-zero
vm.assume(storageSlot != arrayElementLocation(hashedLocationOffset(1, GUARDIANSETS_SLOT, 0), i));
}
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitNewGuardianSet(MODULE, CHAINID, 1, newGuardianSet);
(bytes memory _vm, bytes32 hash) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.assume(storageSlot != hashedLocation(hash, CONSUMED_ACTIONS_SLOT));
proxied.submitNewGuardianSet(_vm);
// The error message is not "governance action already consumed" because the guardian set index is updated,
// and the check for the current guardian set index comes first than the check for action already consumed
vm.expectRevert("not signed by current guardian set");
proxied.submitNewGuardianSet(_vm);
}
function isReservedAddress(address addr) internal view returns (bool) {
return
// Avoid precompiled contracts
addr <= address(0x9) ||
// Wormhole contract does not accept assets
addr == address(impl) ||
// Setup contract
addr == address(setup) ||
// Test contract
addr == address(this) ||
// Cheatcode contract
addr == address(vm) ||
// Create2Deployer address
addr == address(0x4e59b44847b379578588920cA78FbF26c0B4956C);
}
function testSubmitTransferFees(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint256 amount,
bytes32 recipient)
public
unchangedStorage(address(proxied), storageSlot)
{
// Avoid reserved addresses (which will cause the transfer to revert)
vm.assume(!isReservedAddress(address(uint160(uint256(recipient)))));
vm.chainId(EVMCHAINID);
vm.deal(address(proxied), amount);
bytes memory payload = payloadSubmitTransferFees(MODULE, CHAINID, amount, recipient);
(bytes memory _vm, bytes32 hash) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.assume(storageSlot != hashedLocation(hash, CONSUMED_ACTIONS_SLOT));
address payable receiver = payable(address(uint160(uint256(recipient))));
uint256 previousBalance = receiver.balance;
proxied.submitTransferFees(_vm);
assertEq(receiver.balance, previousBalance + amount);
assertEq(address(proxied).balance, 0);
assertEq(true, proxied.governanceActionIsConsumed(hash));
}
function testSubmitTransferFees_Revert_InvalidModule(
bytes32 storageSlot,
uint64 evmChainId,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
bytes32 module,
uint16 chainId,
uint256 amount,
bytes32 recipient)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(module != MODULE);
vm.assume(chainId == 0 || (chainId == CHAINID && evmChainId == EVMCHAINID));
vm.chainId(evmChainId);
vm.deal(address(proxied), amount);
bytes memory payload = payloadSubmitTransferFees(module, CHAINID, amount, recipient);
bytes memory body = abi.encodePacked(
timestamp, nonce, uint16(1), governanceContract, sequence, consistencyLevel, payload);
bytes32 hash = keccak256(abi.encodePacked(keccak256(body)));
bytes memory _vm = bytes.concat(validVmHeader(0), validSignature(testGuardian, hash), body);
vm.expectRevert("invalid Module");
proxied.submitTransferFees(_vm);
}
function testSubmitTransferFees_Revert_InvalidChain(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint16 chainId,
uint256 amount,
bytes32 recipient)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(chainId != CHAINID && chainId != 0);
vm.chainId(EVMCHAINID);
vm.deal(address(proxied), amount);
bytes memory payload = payloadSubmitTransferFees(MODULE, chainId, amount, recipient);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("invalid Chain");
proxied.submitTransferFees(_vm);
}
function testSubmitTransferFees_Revert_InvalidEvmChain(
bytes32 storageSlot,
uint64 evmchainId,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint256 amount,
bytes32 recipient)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(evmchainId != EVMCHAINID);
vm.chainId(evmchainId);
vm.deal(address(proxied), amount);
bytes memory payload = payloadSubmitTransferFees(MODULE, CHAINID, amount, recipient);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("invalid Chain");
proxied.submitTransferFees(_vm);
}
function testSubmitTransferFees_Revert_InvalidGuardianSet(
bytes32 storageSlot,
uint64 evmChainId,
uint32 guardianSetIndex,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint16 chainId,
uint256 amount,
bytes32 recipient)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(guardianSetIndex != 0);
vm.assume(chainId == 0 || (chainId == CHAINID && evmChainId == EVMCHAINID));
vm.chainId(evmChainId);
vm.deal(address(proxied), amount);
bytes memory payload = payloadSubmitTransferFees(MODULE, chainId, amount, recipient);
(bytes memory _vm, ) = validVm(
guardianSetIndex, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
// Since the current version of the test uses only one guardian set,
// in practice only the 'else' branch will be taken
if (guardianSetIndex < proxied.getCurrentGuardianSetIndex()) {
vm.expectRevert("not signed by current guardian set");
} else {
vm.expectRevert("invalid guardian set");
}
proxied.submitTransferFees(_vm);
}
function testSubmitTransferFees_Revert_WrongGovernanceChain(
bytes32 storageSlot,
uint64 evmChainId,
uint32 timestamp,
uint32 nonce,
uint16 emitterChainId,
uint64 sequence,
uint8 consistencyLevel,
uint16 chainId,
uint256 amount,
bytes32 recipient)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(emitterChainId != 1);
vm.assume(chainId == 0 || (chainId == CHAINID && evmChainId == EVMCHAINID));
vm.chainId(evmChainId);
vm.deal(address(proxied), amount);
bytes memory payload = payloadSubmitTransferFees(MODULE, chainId, amount, recipient);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, emitterChainId, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("wrong governance chain");
proxied.submitTransferFees(_vm);
}
function testSubmitTransferFees_Revert_WrongGovernanceContract(
bytes32 storageSlot,
uint64 evmChainId,
uint32 timestamp,
uint32 nonce,
bytes32 emitterAddress,
uint64 sequence,
uint8 consistencyLevel,
uint16 chainId,
uint256 amount,
bytes32 recipient)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(emitterAddress != governanceContract);
vm.assume(chainId == 0 || (chainId == CHAINID && evmChainId == EVMCHAINID));
vm.chainId(evmChainId);
vm.deal(address(proxied), amount);
bytes memory payload = payloadSubmitTransferFees(MODULE, chainId, amount, recipient);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, emitterAddress, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("wrong governance contract");
proxied.submitTransferFees(_vm);
}
function testSubmitTransferFees_Revert_ReplayAttack(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint256 amount,
bytes32 recipient)
public
unchangedStorage(address(proxied), storageSlot)
{
// Avoid reserved addresses (which will cause the transfer to revert)
vm.assume(!isReservedAddress(address(uint160(uint256(recipient)))));
vm.chainId(EVMCHAINID);
vm.deal(address(proxied), amount);
bytes memory payload = payloadSubmitTransferFees(MODULE, CHAINID, amount, recipient);
(bytes memory _vm, bytes32 hash) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.assume(storageSlot != hashedLocation(hash, CONSUMED_ACTIONS_SLOT));
proxied.submitTransferFees(_vm);
vm.expectRevert("governance action already consumed");
proxied.submitTransferFees(_vm);
}
function testSubmitRecoverChainId(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint256 evmChainId,
uint16 newChainId)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(storageSlot != CHAINID_SLOT);
vm.assume(storageSlot != EVMCHAINID_SLOT);
vm.assume(evmChainId != EVMCHAINID);
vm.assume(evmChainId < 2 ** 64);
vm.chainId(evmChainId);
bytes memory payload = payloadSubmitRecoverChainId(MODULE, evmChainId, newChainId);
(bytes memory _vm, bytes32 hash) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.assume(storageSlot != hashedLocation(hash, CONSUMED_ACTIONS_SLOT));
proxied.submitRecoverChainId(_vm);
assertEq(true, proxied.governanceActionIsConsumed(hash));
assertEq(evmChainId, proxied.evmChainId());
assertEq(newChainId, proxied.chainId());
}
function testSubmitRecoverChainId_Revert_NotAFork(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint256 evmChainId,
uint16 newChainId)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(evmChainId != EVMCHAINID);
vm.chainId(EVMCHAINID);
bytes memory payload = payloadSubmitRecoverChainId(MODULE, evmChainId, newChainId);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("not a fork");
proxied.submitRecoverChainId(_vm);
}
function testSubmitRecoverChainId_Revert_InvalidModule(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
bytes32 module,
uint256 evmChainId,
uint16 newChainId)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(module != MODULE);
vm.assume(evmChainId != EVMCHAINID);
vm.assume(evmChainId < 2 ** 64);
vm.chainId(evmChainId);
vm.assume(module != MODULE);
bytes memory payload = payloadSubmitRecoverChainId(module, evmChainId, newChainId);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("invalid Module");
proxied.submitRecoverChainId(_vm);
}
function testSubmitRecoverChainId_Revert_InvalidEVMChain(
bytes32 storageSlot,
uint64 blockChainId,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint256 evmChainId,
uint16 newChainId)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(evmChainId != EVMCHAINID);
vm.assume(evmChainId < 2 ** 64);
vm.assume(blockChainId != evmChainId && blockChainId != EVMCHAINID);
vm.chainId(blockChainId);
bytes memory payload = payloadSubmitRecoverChainId(MODULE, evmChainId, newChainId);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("invalid EVM Chain");
proxied.submitRecoverChainId(_vm);
}
function testSubmitRecoverChainId_Revert_InvalidGuardianSetIndex(
bytes32 storageSlot,
uint32 guardianSetIndex,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint256 evmChainId,
uint16 newChainId)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(guardianSetIndex != 0);
vm.assume(evmChainId != EVMCHAINID);
vm.assume(evmChainId < 2 ** 64);
vm.chainId(evmChainId);
bytes memory payload = payloadSubmitRecoverChainId(MODULE, evmChainId, newChainId);
(bytes memory _vm, ) = validVm(
guardianSetIndex, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
// Since the current version of the test uses only one guardian set,
// in practice only the 'else' branch will be taken
if (guardianSetIndex < proxied.getCurrentGuardianSetIndex()) {
vm.expectRevert("not signed by current guardian set");
} else {
vm.expectRevert("invalid guardian set");
}
proxied.submitRecoverChainId(_vm);
}
function testSubmitRecoverChainId_Revert_WrongGovernanceChain(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint16 emitterChainId,
uint64 sequence,
uint8 consistencyLevel,
uint256 evmChainId,
uint16 newChainId)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(emitterChainId != 1);
vm.assume(evmChainId != EVMCHAINID);
vm.assume(evmChainId < 2 ** 64);
vm.chainId(evmChainId);
bytes memory payload = payloadSubmitRecoverChainId(MODULE, evmChainId, newChainId);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, emitterChainId, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("wrong governance chain");
proxied.submitRecoverChainId(_vm);
}
function testSubmitRecoverChainId_Revert_WrongGovernanceContract(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
bytes32 emitterAddress,
uint64 sequence,
uint8 consistencyLevel,
uint256 evmChainId,
uint16 newChainId)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(emitterAddress != governanceContract);
vm.assume(evmChainId != EVMCHAINID);
vm.assume(evmChainId < 2 ** 64);
vm.chainId(evmChainId);
bytes memory payload = payloadSubmitRecoverChainId(MODULE, evmChainId, newChainId);
(bytes memory _vm, ) = validVm(
0, timestamp, nonce, 1, emitterAddress, sequence, consistencyLevel, payload, testGuardian);
vm.expectRevert("wrong governance contract");
proxied.submitRecoverChainId(_vm);
}
function testSubmitRecoverChainId_Revert_ReplayAttack(
bytes32 storageSlot,
uint32 timestamp,
uint32 nonce,
uint64 sequence,
uint8 consistencyLevel,
uint256 evmChainId,
uint16 newChainId)
public
unchangedStorage(address(proxied), storageSlot)
{
vm.assume(storageSlot != CHAINID_SLOT);
vm.assume(storageSlot != EVMCHAINID_SLOT);
vm.assume(evmChainId != EVMCHAINID);
vm.assume(evmChainId < 2 ** 64);
vm.chainId(evmChainId);
bytes memory payload = payloadSubmitRecoverChainId(MODULE, evmChainId, newChainId);
(bytes memory _vm, bytes32 hash) = validVm(
0, timestamp, nonce, 1, governanceContract, sequence, consistencyLevel, payload, testGuardian);
vm.assume(storageSlot != hashedLocation(hash, CONSUMED_ACTIONS_SLOT));
proxied.submitRecoverChainId(_vm);
// The error message is not "governance action already consumed" because the evmChainId is updated,
// and the check for isFork() comes first than the check for action already consumed
vm.expectRevert("not a fork");
proxied.submitRecoverChainId(_vm);
}
}