| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643 |
- // SPDX-License-Identifier: Apache 2
- pragma solidity ^0.8.0;
- import "forge-std/Test.sol";
- import "@pythnetwork/entropy-sdk-solidity/EntropyStructs.sol";
- import "../contracts/executor/ExecutorUpgradable.sol";
- import "./utils/WormholeTestUtils.t.sol";
- import "./utils/InvalidMagic.t.sol";
- contract ExecutorTest is Test, WormholeTestUtils {
- Wormhole public wormhole;
- ExecutorUpgradable public executor;
- ExecutorUpgradable public executor2;
- TestCallable public callable;
- InvalidMagic public executorInvalidMagic;
- uint16 OWNER_CHAIN_ID = 7;
- bytes32 OWNER_EMITTER = bytes32(uint256(1));
- uint8 NUM_SIGNERS = 1;
- function setUp() public {
- address _wormhole = setUpWormholeReceiver(NUM_SIGNERS);
- ExecutorUpgradable _executor = new ExecutorUpgradable();
- ERC1967Proxy _proxy = new ERC1967Proxy(address(_executor), "");
- executor = ExecutorUpgradable(payable(address(_proxy)));
- executor2 = new ExecutorUpgradable();
- executorInvalidMagic = new InvalidMagic();
- executor.initialize(
- _wormhole,
- 0,
- CHAIN_ID,
- OWNER_CHAIN_ID,
- OWNER_EMITTER
- );
- callable = new TestCallable();
- }
- function testExecute(
- address callAddress,
- bytes memory callData,
- uint64 sequence,
- uint value
- ) internal returns (bytes memory vaa) {
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- CHAIN_ID,
- address(executor),
- callAddress,
- value,
- callData
- );
- vaa = generateVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- OWNER_EMITTER,
- sequence,
- payload,
- NUM_SIGNERS
- );
- executor.execute(vaa);
- }
- function getTestUpgradeVaa(
- address newImplementation,
- uint value
- ) internal view returns (bytes memory vaa) {
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- CHAIN_ID,
- address(executor),
- address(executor),
- value,
- abi.encodeWithSelector(
- ExecutorUpgradable.upgradeTo.selector,
- newImplementation
- )
- );
- vaa = generateVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- OWNER_EMITTER,
- 1,
- payload,
- NUM_SIGNERS
- );
- }
- function testExecutorOwnerChainId() public {
- uint chainId = executor.getOwnerChainId();
- assertEq(chainId, OWNER_CHAIN_ID);
- }
- function testExecutorOwnerEmitterAddress() public {
- bytes32 ownerEmitterAddress = executor.getOwnerEmitterAddress();
- assertEq(ownerEmitterAddress, OWNER_EMITTER);
- }
- function testExecutorOwner() public {
- assertEq(address(executor), executor.owner());
- }
- function testExternaUpgradeCallFails() public {
- vm.expectRevert("Ownable: caller is not the owner");
- executor.upgradeTo(address(executor2));
- }
- function testUpgradeCallSucceedsForContractWithCorrectMagic() public {
- bytes memory vaa = getTestUpgradeVaa(address(executor2), 0);
- executor.execute(vaa);
- }
- function testUpgradeCallFailsForNotUUPSContract() public {
- bytes memory vaa = getTestUpgradeVaa(address(callable), 0);
- vm.expectRevert("ERC1967Upgrade: new implementation is not UUPS");
- executor.execute(vaa);
- }
- function testUpgradeCallFailsForInvalidMagic() public {
- bytes memory vaa = getTestUpgradeVaa(address(executorInvalidMagic), 0);
- vm.expectRevert(ExecutorErrors.InvalidMagicValue.selector);
- executor.execute(vaa);
- }
- function testLastExecutedSequenceUpdateOnSucceed() public {
- callable.reset();
- uint32 c = callable.fooCount();
- uint oldSequence = executor.getLastExecutedSequence();
- uint64 sequence = 1;
- assertEq(callable.lastCaller(), address(bytes20(0)));
- testExecute(
- address(callable),
- abi.encodeWithSelector(ICallable.foo.selector),
- sequence,
- 0
- );
- uint newSequence = executor.getLastExecutedSequence();
- assertGt(newSequence, oldSequence);
- assertEq(newSequence, sequence);
- assertEq(callable.fooCount(), c + 1);
- assertEq(callable.lastCaller(), address(executor));
- // Sanity check to make sure the check above is meaningful.
- assert(address(executor) != address(this));
- }
- function testLastExecutedSequenceNoChangeOnFail() public {
- uint oldSequence = executor.getLastExecutedSequence();
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- CHAIN_ID,
- address(executor),
- address(callable),
- uint(0),
- abi.encodeWithSelector(ICallable.reverts.selector)
- );
- bytes memory vaa = generateVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- OWNER_EMITTER,
- 1,
- payload,
- NUM_SIGNERS
- );
- vm.expectRevert("call should revert");
- executor.execute(vaa);
- uint newSequence = executor.getLastExecutedSequence();
- assertEq(newSequence, oldSequence);
- }
- function testCallSucceeds() public {
- callable.reset();
- uint32 c = callable.fooCount();
- assertEq(callable.lastCaller(), address(bytes20(0)));
- testExecute(
- address(callable),
- abi.encodeWithSelector(ICallable.foo.selector),
- 1,
- 0
- );
- assertEq(callable.fooCount(), c + 1);
- assertEq(callable.lastCaller(), address(executor));
- // Sanity check to make sure the check above is meaningful.
- assert(address(executor) != address(this));
- }
- function testCallWithValueSucceeds() public {
- callable.reset();
- uint32 c = callable.fooCount();
- assertEq(callable.lastCaller(), address(bytes20(0)));
- uint value = 1;
- vm.deal(address(executor), value);
- testExecute(
- address(callable),
- abi.encodeWithSelector(ICallable.fooPayable.selector),
- 1,
- value
- );
- assertEq(callable.fooCount(), c + 1);
- assertEq(callable.lastCaller(), address(executor));
- assertEq(address(executor).balance, 0);
- assertEq(address(callable).balance, value);
- // Sanity check to make sure the check above is meaningful.
- assert(address(executor) != address(this));
- }
- function testCallWithValueInsufficientBalance() public {
- callable.reset();
- assertEq(callable.lastCaller(), address(bytes20(0)));
- uint value = 5;
- vm.deal(address(executor), 1);
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- CHAIN_ID,
- address(executor),
- address(callable),
- value,
- abi.encodeWithSelector(ICallable.fooPayable.selector)
- );
- bytes memory vaa = generateVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- OWNER_EMITTER,
- 1,
- payload,
- NUM_SIGNERS
- );
- vm.expectRevert();
- executor.execute(vaa);
- }
- function testCallWithArgsSucceeds() public {
- callable.reset();
- uint32 c = callable.fooCount();
- assertEq(callable.lastCaller(), address(bytes20(0)));
- testExecute(
- address(callable),
- abi.encodeWithSelector(ICallable.fooWithArgs.selector, 17),
- 1,
- 0
- );
- assertEq(callable.fooCount(), c + 17);
- assertEq(callable.lastCaller(), address(executor));
- // Sanity check to make sure the check above is meaningful.
- assert(address(executor) != address(this));
- }
- function testCallWithArgsAndValueSucceeds() public {
- callable.reset();
- uint32 c = callable.fooCount();
- assertEq(callable.lastCaller(), address(bytes20(0)));
- uint value = 1;
- vm.deal(address(executor), value);
- testExecute(
- address(callable),
- abi.encodeWithSelector(ICallable.fooPayableWithArgs.selector, 17),
- 1,
- value
- );
- assertEq(callable.fooCount(), c + 17);
- assertEq(callable.lastCaller(), address(executor));
- assertEq(address(executor).balance, 0);
- assertEq(address(callable).balance, value);
- // Sanity check to make sure the check above is meaningful.
- assert(address(executor) != address(this));
- }
- function testCallerAddress() public {
- uint32 c = callable.fooCount();
- testExecute(
- address(callable),
- abi.encodeWithSelector(ICallable.foo.selector),
- 1,
- 0
- );
- assertEq(callable.fooCount(), c + 1);
- }
- function testIncorrectVaa() public {
- string[5] memory forgeItems = [
- "vaaSignature",
- "vaaVersion",
- "vaaGuardianSetIndex",
- "vaaNumSigners+",
- "vaaNumSigners-"
- ];
- for (uint i = 0; i < forgeItems.length; i++) {
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- CHAIN_ID,
- address(executor),
- address(callable),
- uint(0),
- abi.encodeWithSelector(ICallable.foo.selector)
- );
- bytes memory vaa = forgeVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- OWNER_EMITTER,
- 1,
- payload,
- NUM_SIGNERS,
- bytes(forgeItems[i])
- );
- // ExecutorErrors.InvalidWormholeVaa.selector
- vm.expectRevert();
- executor.execute(vaa);
- }
- }
- function testIncorrectOwnerEmitterAddress() public {
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- CHAIN_ID,
- address(executor),
- address(callable),
- uint(0),
- abi.encodeWithSelector(ICallable.foo.selector)
- );
- bytes memory vaa = generateVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- bytes32(uint256(2)),
- 1,
- payload,
- NUM_SIGNERS
- );
- vm.expectRevert(ExecutorErrors.UnauthorizedEmitter.selector);
- executor.execute(vaa);
- }
- function testIncorrectOwnerEmitterChainId() public {
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- CHAIN_ID,
- address(executor),
- address(callable),
- uint(0),
- abi.encodeWithSelector(ICallable.foo.selector)
- );
- bytes memory vaa = generateVaa(
- uint32(block.timestamp),
- 8,
- OWNER_EMITTER,
- 1,
- payload,
- NUM_SIGNERS
- );
- vm.expectRevert(ExecutorErrors.UnauthorizedEmitter.selector);
- executor.execute(vaa);
- }
- function testOutOfOrder() public {
- testExecute(
- address(callable),
- abi.encodeWithSelector(ICallable.foo.selector),
- 3,
- 0
- );
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- CHAIN_ID,
- address(executor),
- address(callable),
- uint(0),
- abi.encodeWithSelector(ICallable.foo.selector)
- );
- bytes memory vaa = generateVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- OWNER_EMITTER,
- 3,
- payload,
- NUM_SIGNERS
- );
- vm.expectRevert(ExecutorErrors.MessageOutOfOrder.selector);
- executor.execute(vaa);
- callable.reset();
- testExecute(
- address(callable),
- abi.encodeWithSelector(ICallable.foo.selector),
- 4,
- 0
- );
- assertEq(callable.fooCount(), 1);
- }
- function testInvalidPayload() public {
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- CHAIN_ID,
- address(executor),
- address(callable),
- uint(0),
- abi.encodeWithSelector(ICallable.foo.selector)
- );
- bytes memory shortPayload = BytesLib.slice(
- payload,
- 0,
- payload.length - 1
- );
- bytes memory shortVaa = generateVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- OWNER_EMITTER,
- 1,
- shortPayload,
- NUM_SIGNERS
- );
- vm.expectRevert();
- executor.execute(shortVaa);
- }
- function testIncorrectTargetChainId() public {
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- uint16(3),
- address(executor),
- address(callable),
- uint(0),
- abi.encodeWithSelector(ICallable.foo.selector)
- );
- bytes memory vaa = generateVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- OWNER_EMITTER,
- 1,
- payload,
- NUM_SIGNERS
- );
- vm.expectRevert(ExecutorErrors.InvalidGovernanceTarget.selector);
- executor.execute(vaa);
- }
- function testIncorrectTargetAddress() public {
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- CHAIN_ID,
- address(0x1),
- address(callable),
- uint(0),
- abi.encodeWithSelector(ICallable.foo.selector)
- );
- bytes memory vaa = generateVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- OWNER_EMITTER,
- 1,
- payload,
- NUM_SIGNERS
- );
- vm.expectRevert(ExecutorErrors.DeserializationError.selector);
- executor.execute(vaa);
- }
- function testIncorrectAction() public {
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- uint8(17),
- CHAIN_ID,
- address(executor),
- address(callable),
- uint(0),
- abi.encodeWithSelector(ICallable.foo.selector)
- );
- bytes memory vaa = generateVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- OWNER_EMITTER,
- 1,
- payload,
- NUM_SIGNERS
- );
- vm.expectRevert();
- executor.execute(vaa);
- }
- function testCallReverts() public {
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- CHAIN_ID,
- address(executor),
- address(callable),
- uint(0),
- abi.encodeWithSelector(ICallable.reverts.selector)
- );
- bytes memory vaa = generateVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- OWNER_EMITTER,
- 1,
- payload,
- NUM_SIGNERS
- );
- vm.expectRevert("call should revert");
- executor.execute(vaa);
- }
- function testCallToEoaReverts() public {
- bytes memory payload = abi.encodePacked(
- uint32(0x5054474d),
- PythGovernanceInstructions.GovernanceModule.EvmExecutor,
- Executor.ExecutorAction.Execute,
- CHAIN_ID,
- address(executor),
- address(100),
- uint(0),
- abi.encodeWithSelector(ICallable.foo.selector)
- );
- bytes memory vaa = generateVaa(
- uint32(block.timestamp),
- OWNER_CHAIN_ID,
- OWNER_EMITTER,
- 1,
- payload,
- NUM_SIGNERS
- );
- vm.expectRevert(ExecutorErrors.InvalidContractTarget.selector);
- executor.execute(vaa);
- }
- }
- interface ICallable {
- function foo() external;
- function fooPayable() external payable;
- function fooWithArgs(uint32 inc) external;
- function fooPayableWithArgs(uint32 inc) external payable;
- function reverts() external;
- function reset() external;
- }
- contract TestCallable is ICallable {
- uint32 public fooCount = 0;
- address public lastCaller = address(bytes20(0));
- constructor() {}
- function reset() external override {
- fooCount = 0;
- lastCaller = address(bytes20(0));
- }
- function foo() external override {
- fooCount += 1;
- lastCaller = msg.sender;
- }
- function fooPayable() external payable override {
- fooCount += 1;
- lastCaller = msg.sender;
- }
- function fooWithArgs(uint32 inc) external override {
- fooCount += inc;
- lastCaller = msg.sender;
- }
- function fooPayableWithArgs(uint32 inc) external payable override {
- fooCount += inc;
- lastCaller = msg.sender;
- }
- function reverts() external pure override {
- revert("call should revert");
- }
- }
|