wormhole-circle-integration/evm/forge/tests/ForkSlots.t.sol

355 lines
14 KiB
Solidity

// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "forge-std/console.sol";
import {IWormhole} from "src/interfaces/IWormhole.sol";
import {ICircleIntegration} from "src/interfaces/ICircleIntegration.sol";
import {Utils} from "src/libraries/Utils.sol";
import {Implementation} from "src/contracts/CircleIntegration/Implementation.sol";
import {CircleIntegrationOverride} from "test-helpers/libraries/CircleIntegrationOverride.sol";
import {SlotCheck} from "test-helpers/libraries/SlotCheck.sol";
import {WormholeOverride} from "test-helpers/libraries/WormholeOverride.sol";
contract ForkSlots is Test {
using CircleIntegrationOverride for *;
using WormholeOverride for *;
using Utils for address;
using SlotCheck for *;
bytes32 constant GOVERNANCE_MODULE =
0x000000000000000000000000000000436972636c65496e746567726174696f6e;
address constant FORKED_CIRCLE_INTEGRATION_ADDRESS = 0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c;
ICircleIntegration forked;
address forkedAddress;
IWormhole wormhole;
// Expected at slot 0x0.
uint16 expectedChainId;
uint8 expectedWormholeFinality;
uint32 expectedLocalDomain;
address expectedWormholeAddress;
uint16 expectedGovernanceChainId;
// Expected at slot 0x1.
bytes32 expectedGovernanceContract;
// Expected at slot 0x2.
address expectedCircleBridgeAddress;
// Expected at slot 0x3.
address expectedCircleTransmitterAddress;
// Expected at slot 0x4.
address expectedCircleTokenMinterAddress;
// Expected at slot 0xa.
uint256 expectedEvmChain;
function setUp() public {
forked = ICircleIntegration(FORKED_CIRCLE_INTEGRATION_ADDRESS);
forked.setUpOverride(uint256(vm.envBytes32("TESTING_DEVNET_GUARDIAN")));
forkedAddress = address(forked);
wormhole = forked.wormhole();
// Set expected values.
expectedChainId = forked.chainId();
expectedWormholeFinality = forked.wormholeFinality();
expectedLocalDomain = forked.localDomain();
expectedWormholeAddress = address(forked.wormhole());
expectedGovernanceChainId = forked.governanceChainId();
expectedGovernanceContract = forked.governanceContract();
expectedCircleBridgeAddress = address(forked.circleBridge());
expectedCircleTransmitterAddress = address(forked.circleTransmitter());
expectedCircleTokenMinterAddress = address(forked.circleTokenMinter());
expectedEvmChain = forked.evmChain();
}
function test_UpgradeForkAndCheckSlots() public {
// Deploy new implementation.
Implementation implementation = new Implementation(
address(wormhole),
vm.envAddress("TESTING_CIRCLE_BRIDGE_ADDRESS") // tokenMessenger
);
// Should not be initialized yet.
bool isInitialized = forked.isInitialized(address(implementation));
assertFalse(isInitialized, "already initialized");
(IWormhole.VM memory vaa, bytes memory encodedVaa) = wormhole.craftGovernanceVaa(
GOVERNANCE_MODULE,
3, // action
forked.chainId(),
69, // sequence
abi.encodePacked(address(implementation).toUniversalAddress())
);
// This VAA should not have been consumed yet.
bool isVaaConsumed = forked.isMessageConsumed(vaa.hash);
assertFalse(isVaaConsumed, "VAA already consumed");
// Before upgrading, fetch some expected values.
uint16 expectedRegisteredChainId = 6; // Avalanche (Fuji)
bytes32 expectedEmitter = forked.getRegisteredEmitter(expectedRegisteredChainId);
uint32 expectedCctpDomain = forked.getDomainFromChainId(expectedRegisteredChainId);
// Check slots before upgrade.
{
bytes32 slotZeroData = vm.load(address(forked), bytes32(0));
// If the data is already zeroed, check the remaining zeroed slots. Otherwise check that
// the slots are the expected values from the existing getters.
if (slotZeroData != 0) {
// Now check slots that will be zeroed.
uint256 bitOffset;
// First 2 bytes is chain ID.
assertEq(
uint16(uint256(slotZeroData >> bitOffset)),
expectedChainId,
"slot 0x0 not equal to expected before upgrade"
);
bitOffset += 16;
// Next byte is wormhole finality.
assertEq(
uint8(uint256(slotZeroData >> bitOffset)),
expectedWormholeFinality,
"slot 0x0 not equal to expected before upgrade"
);
bitOffset += 8;
// Next 4 bytes is local domain.
assertEq(
uint32(uint256(slotZeroData >> bitOffset)),
expectedLocalDomain,
"slot 0x0 not equal to expected before upgrade"
);
bitOffset += 32;
// Next 20 bytes is wormhole address.
assertEq(
address(uint160(uint256(slotZeroData >> bitOffset))),
expectedWormholeAddress,
"slot 0x0 not equal to expected before upgrade"
);
bitOffset += 160;
// Next 2 bytes is governance chain ID.
assertEq(
uint16(uint256(slotZeroData >> bitOffset)),
expectedGovernanceChainId,
"slot 0x0 not equal to expected before upgrade"
);
bitOffset += 16;
// Remaining bytes are zero.
assertEq(
uint256(slotZeroData >> bitOffset),
0,
"slot 0x0 not equal to expected before upgrade"
);
}
if (slotZeroData == 0) {
assertTrue(
forkedAddress.slotValueZero(0x1),
"slot 0x1 not equal to expected before upgrade"
);
assertTrue(
forkedAddress.slotValueZero(0x2),
"slot 0x2 not equal to expected before upgrade"
);
assertTrue(
forkedAddress.slotValueZero(0x3),
"slot 0x3 not equal to expected before upgrade"
);
assertTrue(
forkedAddress.slotValueZero(0x4),
"slot 0x4 not equal to expected before upgrade"
);
} else {
assertTrue(
forkedAddress.slotValueEquals(0x1, expectedGovernanceContract),
"slot 0x1 not equal to expected before upgrade"
);
assertTrue(
forkedAddress.slotValueEquals(0x2, expectedCircleBridgeAddress),
"slot 0x2 not equal to expected before upgrade"
);
assertTrue(
forkedAddress.slotValueEquals(0x3, expectedCircleTransmitterAddress),
"slot 0x3 not equal to expected before upgrade"
);
assertTrue(
forkedAddress.slotValueEquals(0x4, expectedCircleTokenMinterAddress),
"slot 0x4 not equal to expected before upgrade"
);
}
assertTrue(
forkedAddress.slotValueEquals(
keccak256(abi.encode(address(implementation), uint256(0x5))), isInitialized
),
"mapped slot 0x5 not equal to expected before upgrade"
);
assertTrue(
forkedAddress.slotValueEquals(
keccak256(abi.encode(expectedRegisteredChainId, uint256(0x6))), expectedEmitter
),
"mapped slot 0x6 not equal to expected before upgrade"
);
assertTrue(
forkedAddress.slotValueEquals(
keccak256(abi.encode(expectedRegisteredChainId, uint256(0x7))),
expectedCctpDomain
),
"mapped slot 0x7 not equal to expected before upgrade"
);
assertTrue(
forkedAddress.slotValueEquals(
keccak256(abi.encode(expectedCctpDomain, uint256(0x8))),
expectedRegisteredChainId
),
"mapped slot 0x8 not equal to expected before upgrade"
);
assertTrue(
forkedAddress.slotValueEquals(
keccak256(abi.encode(vaa.hash, uint256(0x9))), isVaaConsumed
),
"mapped slot 0x9 not equal to expected before upgrade"
);
if (slotZeroData == 0) {
assertTrue(
forkedAddress.slotValueZero(0xa),
"slot 0xa not equal to expected before upgrade"
);
} else {
assertTrue(
forkedAddress.slotValueEquals(0xa, expectedEvmChain),
"slot 0xa not equal to expected before upgrade"
);
}
}
// Upgrade contract.
forked.upgradeContract(encodedVaa);
// Now initialized.
isInitialized = forked.isInitialized(address(implementation));
assertTrue(isInitialized, "implementation not initialized");
// VAA now consumed.
isVaaConsumed = forked.isMessageConsumed(vaa.hash);
assertTrue(isVaaConsumed, "VAA not consumed");
// Now check all slots that were checked before.
{
assertTrue(
forkedAddress.slotValueZero(bytes32(0)),
"slot 0x0 not equal to expected after upgrade"
);
assertTrue(
forkedAddress.slotValueZero(0x1), "slot 0x1 not equal to expected after upgrade"
);
assertTrue(
forkedAddress.slotValueZero(0x2), "slot 0x2 not equal to expected after upgrade"
);
assertTrue(
forkedAddress.slotValueZero(0x3), "slot 0x3 not equal to expected after upgrade"
);
assertTrue(
forkedAddress.slotValueZero(0x4), "slot 0x4 not equal to expected after upgrade"
);
assertTrue(
forkedAddress.slotValueEquals(
keccak256(abi.encode(address(implementation), uint256(0x5))), isInitialized
),
"mapped slot 0x5 not equal to expected after upgrade"
);
assertTrue(
forkedAddress.slotValueEquals(
keccak256(abi.encode(expectedRegisteredChainId, uint256(0x6))), expectedEmitter
),
"mapped slot 0x6 not equal to expected after upgrade"
);
assertTrue(
forkedAddress.slotValueEquals(
keccak256(abi.encode(expectedRegisteredChainId, uint256(0x7))),
expectedCctpDomain
),
"mapped slot 0x7 not equal to expected after upgrade"
);
assertTrue(
forkedAddress.slotValueEquals(
keccak256(abi.encode(expectedCctpDomain, uint256(0x8))),
expectedRegisteredChainId
),
"mapped slot 0x8 not equal to expected after upgrade"
);
assertTrue(
forkedAddress.slotValueEquals(
keccak256(abi.encode(vaa.hash, uint256(0x9))), isVaaConsumed
),
"mapped slot 0x9 not equal to expected after upgrade"
);
assertTrue(
forkedAddress.slotValueZero(0xa), "slot 0xa not equal to expected after upgrade"
);
}
// Make sure getters still retrieve expected values.
assertEq(forked.chainId(), expectedChainId, "chainId not equal to expected after upgrade");
assertEq(
forked.wormholeFinality(),
expectedWormholeFinality,
"wormholeFinality not equal to expected after upgrade"
);
assertEq(
forked.localDomain(),
expectedLocalDomain,
"localDomain not equal to expected after upgrade"
);
assertEq(
address(forked.wormhole()),
expectedWormholeAddress,
"wormholeAddress not equal to expected after upgrade"
);
assertEq(
forked.governanceChainId(),
expectedGovernanceChainId,
"governanceChainId not equal to expected after upgrade"
);
assertEq(
forked.governanceContract(),
expectedGovernanceContract,
"governanceContract not equal to expected after upgrade"
);
assertEq(
address(forked.circleBridge()),
expectedCircleBridgeAddress,
"circleBridgeAddress not equal to expected after upgrade"
);
assertEq(
address(forked.circleTransmitter()),
expectedCircleTransmitterAddress,
"circleTransmitterAddress not equal to expected after upgrade"
);
assertEq(
address(forked.circleTokenMinter()),
expectedCircleTokenMinterAddress,
"circleTokenMinterAddress not equal to expected after upgrade"
);
assertEq(
forked.evmChain(), expectedEvmChain, "evmChain not equal to expected after upgrade"
);
}
}