1222 lines
48 KiB
Solidity
1222 lines
48 KiB
Solidity
// SPDX-License-Identifier: Apache 2
|
|
pragma solidity ^0.8.13;
|
|
|
|
import "forge-std/Test.sol";
|
|
import "forge-std/console.sol";
|
|
|
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
import {BytesLib} from "wormhole/libraries/external/BytesLib.sol";
|
|
|
|
import {IWormhole} from "wormhole/interfaces/IWormhole.sol";
|
|
import {ICircleIntegration} from "../src/interfaces/ICircleIntegration.sol";
|
|
|
|
import {CircleIntegrationStructs} from "../src/circle_integration/CircleIntegrationStructs.sol";
|
|
import {CircleIntegrationSetup} from "../src/circle_integration/CircleIntegrationSetup.sol";
|
|
import {CircleIntegrationImplementation} from "../src/circle_integration/CircleIntegrationImplementation.sol";
|
|
import {CircleIntegrationProxy} from "../src/circle_integration/CircleIntegrationProxy.sol";
|
|
|
|
import {WormholeSimulator} from "wormhole-forge-sdk/WormholeSimulator.sol";
|
|
|
|
interface IUSDC is IERC20 {
|
|
function mint(address to, uint256 amount) external;
|
|
function configureMinter(address minter, uint256 minterAllowedAmount) external;
|
|
function masterMinter() external view returns (address);
|
|
function owner() external view returns (address);
|
|
function blacklister() external view returns (address);
|
|
}
|
|
|
|
contract CircleIntegrationTest is Test {
|
|
using BytesLib for bytes;
|
|
|
|
bytes32 constant GOVERNANCE_MODULE = 0x000000000000000000000000000000436972636c65496e746567726174696f6e;
|
|
|
|
uint8 constant GOVERNANCE_UPDATE_WORMHOLE_FINALITY = 1;
|
|
uint8 constant GOVERNANCE_REGISTER_EMITTER_AND_DOMAIN = 2;
|
|
uint8 constant GOVERNANCE_REGISTER_ACCEPTED_TOKEN = 3;
|
|
uint8 constant GOVERNANCE_REGISTER_TARGET_CHAIN_TOKEN = 4;
|
|
uint8 constant GOVERNANCE_UPGRADE_CONTRACT = 5;
|
|
|
|
// USDC
|
|
IUSDC usdc;
|
|
|
|
// dependencies
|
|
WormholeSimulator wormholeSimulator;
|
|
IWormhole wormhole;
|
|
|
|
ICircleIntegration circleIntegration;
|
|
|
|
// foreign
|
|
bytes32 foreignUsdc;
|
|
|
|
function maxUSDCAmountToMint() public view returns (uint256) {
|
|
return type(uint256).max - usdc.totalSupply();
|
|
}
|
|
|
|
function mintUSDC(uint256 amount) public {
|
|
require(amount <= maxUSDCAmountToMint(), "total supply overflow");
|
|
usdc.mint(address(this), amount);
|
|
}
|
|
|
|
function setupWormhole() public {
|
|
// Set up this chain's Wormhole
|
|
wormholeSimulator = new WormholeSimulator(
|
|
vm.envAddress("TESTING_WORMHOLE_ADDRESS"), uint256(vm.envBytes32("TESTING_DEVNET_GUARDIAN")));
|
|
wormhole = wormholeSimulator.wormhole();
|
|
}
|
|
|
|
function setupUSDC() public {
|
|
usdc = IUSDC(vm.envAddress("TESTING_USDC_TOKEN_ADDRESS"));
|
|
|
|
(, bytes memory queriedDecimals) = address(usdc).staticcall(abi.encodeWithSignature("decimals()"));
|
|
uint8 decimals = abi.decode(queriedDecimals, (uint8));
|
|
require(decimals == 6, "wrong USDC");
|
|
|
|
// spoof .configureMinter() call with the master minter account
|
|
// allow this test contract to mint USDC
|
|
vm.prank(usdc.masterMinter());
|
|
usdc.configureMinter(address(this), type(uint256).max);
|
|
|
|
uint256 amount = 42069;
|
|
mintUSDC(amount);
|
|
require(usdc.balanceOf(address(this)) == amount);
|
|
}
|
|
|
|
function setupCircleIntegration() public {
|
|
// deploy Setup
|
|
CircleIntegrationSetup setup = new CircleIntegrationSetup();
|
|
|
|
// deploy Implementation
|
|
CircleIntegrationImplementation implementation = new CircleIntegrationImplementation();
|
|
|
|
// deploy Proxy
|
|
CircleIntegrationProxy proxy = new CircleIntegrationProxy(
|
|
address(setup),
|
|
abi.encodeWithSelector(
|
|
bytes4(keccak256("setup(address,address,uint8,address,uint16,bytes32)")),
|
|
address(implementation),
|
|
address(wormhole),
|
|
uint8(1), // finality
|
|
vm.envAddress("TESTING_CIRCLE_BRIDGE_ADDRESS"), // circleBridge
|
|
uint16(1),
|
|
bytes32(0x0000000000000000000000000000000000000000000000000000000000000004)
|
|
)
|
|
);
|
|
|
|
circleIntegration = ICircleIntegration(address(proxy));
|
|
}
|
|
|
|
function setUp() public {
|
|
// set up circle contracts (transferring ownership to address(this), etc)
|
|
setupUSDC();
|
|
|
|
// set up wormhole simulator
|
|
setupWormhole();
|
|
|
|
// now our contract
|
|
setupCircleIntegration();
|
|
|
|
foreignUsdc = bytes32(uint256(uint160(vm.envAddress("TESTING_FOREIGN_USDC_TOKEN_ADDRESS"))));
|
|
}
|
|
|
|
function registerToken(address token) public {
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_ACCEPTED_TOKEN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(bytes12(0), token)
|
|
);
|
|
|
|
// Register and should now be accepted.
|
|
circleIntegration.registerAcceptedToken(encodedMessage);
|
|
}
|
|
|
|
function registerContract(uint16 foreignChain, bytes32 foreignEmitter, uint32 domain) public {
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_EMITTER_AND_DOMAIN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(foreignChain, foreignEmitter, domain)
|
|
);
|
|
|
|
// Register emitter and domain.
|
|
circleIntegration.registerEmitterAndDomain(encodedMessage);
|
|
}
|
|
|
|
function prepareCircleIntegrationTest(uint256 amount) public {
|
|
// Register USDC with CircleIntegration
|
|
registerToken(address(usdc));
|
|
|
|
// Set up USDC token for test
|
|
if (amount > 0) {
|
|
// First mint USDC.
|
|
mintUSDC(amount);
|
|
|
|
// Next set allowance.
|
|
usdc.approve(address(circleIntegration), amount);
|
|
}
|
|
}
|
|
|
|
function testEncodeDepositWithPayload(
|
|
bytes32 token,
|
|
uint256 amount,
|
|
uint32 sourceDomain,
|
|
uint32 targetDomain,
|
|
uint64 nonce,
|
|
bytes32 fromAddress,
|
|
bytes32 mintRecipient,
|
|
bytes memory payload
|
|
) public {
|
|
vm.assume(token != bytes32(0));
|
|
vm.assume(amount > 0);
|
|
vm.assume(targetDomain != sourceDomain);
|
|
vm.assume(nonce > 0);
|
|
vm.assume(fromAddress != bytes32(0));
|
|
vm.assume(mintRecipient != bytes32(0));
|
|
vm.assume(payload.length > 0);
|
|
|
|
ICircleIntegration.DepositWithPayload memory deposit;
|
|
deposit.token = token;
|
|
deposit.amount = amount;
|
|
|
|
deposit.sourceDomain = sourceDomain;
|
|
deposit.targetDomain = targetDomain;
|
|
|
|
deposit.nonce = nonce;
|
|
deposit.fromAddress = fromAddress;
|
|
deposit.mintRecipient = mintRecipient;
|
|
deposit.payload = payload;
|
|
|
|
bytes memory serialized = circleIntegration.encodeDepositWithPayload(deposit);
|
|
|
|
// payload ID
|
|
require(serialized.toUint8(0) == 1, "invalid payload");
|
|
|
|
// token
|
|
for (uint256 i = 0; i < 32;) {
|
|
require(deposit.token[i] == serialized[i + 1], "invalid token serialization");
|
|
unchecked {
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
// amount
|
|
for (uint256 i = 0; i < 32;) {
|
|
require(bytes32(deposit.amount)[i] == serialized[i + 33], "invalid amount serialization");
|
|
unchecked {
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
// sourceDomain 65
|
|
for (uint256 i = 0; i < 4;) {
|
|
require(bytes4(deposit.sourceDomain)[i] == serialized[i + 65], "invalid sourceDomain serialization");
|
|
unchecked {
|
|
i += 1;
|
|
}
|
|
}
|
|
// targetDomain 69 (hehe)
|
|
for (uint256 i = 0; i < 4;) {
|
|
require(bytes4(deposit.targetDomain)[i] == serialized[i + 69], "invalid targetDomain serialization");
|
|
unchecked {
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
// nonce
|
|
for (uint256 i = 0; i < 8;) {
|
|
require(bytes8(deposit.nonce)[i] == serialized[i + 73], "invalid nonce serialization");
|
|
unchecked {
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
// fromAddress
|
|
for (uint256 i = 0; i < 8;) {
|
|
require(deposit.fromAddress[i] == serialized[i + 81], "invalid fromAddress serialization");
|
|
unchecked {
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
// mintRecipient
|
|
for (uint256 i = 0; i < 8;) {
|
|
require(deposit.mintRecipient[i] == serialized[i + 113], "invalid mintRecipient serialization");
|
|
unchecked {
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
// payload length
|
|
uint256 payloadLen = deposit.payload.length;
|
|
for (uint256 i = 0; i < 2;) {
|
|
require(bytes32(payloadLen)[i + 30] == serialized[i + 145], "invalid payload length serialization");
|
|
unchecked {
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
// payload
|
|
for (uint256 i = 0; i < payloadLen;) {
|
|
require(deposit.payload[i] == serialized[i + 147], "invalid payload serialization");
|
|
unchecked {
|
|
i += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
function testDecodeDepositWithPayload(
|
|
bytes32 token,
|
|
uint256 amount,
|
|
uint32 sourceDomain,
|
|
uint32 targetDomain,
|
|
uint64 nonce,
|
|
bytes32 fromAddress,
|
|
bytes32 mintRecipient,
|
|
bytes memory payload
|
|
) public {
|
|
vm.assume(token != bytes32(0));
|
|
vm.assume(amount > 0);
|
|
vm.assume(targetDomain != sourceDomain);
|
|
vm.assume(nonce > 0);
|
|
vm.assume(fromAddress != bytes32(0));
|
|
vm.assume(mintRecipient != bytes32(0));
|
|
vm.assume(payload.length > 0);
|
|
|
|
ICircleIntegration.DepositWithPayload memory expected;
|
|
expected.token = token;
|
|
expected.amount = amount;
|
|
|
|
expected.sourceDomain = 0;
|
|
expected.targetDomain = 1;
|
|
|
|
expected.nonce = nonce;
|
|
expected.fromAddress = fromAddress;
|
|
expected.mintRecipient = mintRecipient;
|
|
expected.payload = payload;
|
|
|
|
bytes memory serialized = circleIntegration.encodeDepositWithPayload(expected);
|
|
|
|
ICircleIntegration.DepositWithPayload memory deposit = circleIntegration.decodeDepositWithPayload(serialized);
|
|
require(deposit.token == expected.token, "token != expected");
|
|
require(deposit.amount == expected.amount, "amount != expected");
|
|
require(deposit.sourceDomain == expected.sourceDomain, "sourceDomain != expected");
|
|
require(deposit.targetDomain == expected.targetDomain, "targetDomain != expected");
|
|
require(deposit.nonce == expected.nonce, "nonce != expected");
|
|
require(deposit.fromAddress == expected.fromAddress, "fromAddress != expected");
|
|
require(deposit.mintRecipient == expected.mintRecipient, "mintRecipient != expected");
|
|
|
|
for (uint256 i = 0; i < deposit.payload.length;) {
|
|
require(deposit.payload[i] == expected.payload[i], "payload != expected");
|
|
unchecked {
|
|
i += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
function testCannotConsumeGovernanceMessageInvalidGovernanceChainId(uint16 governanceChainId, uint8 action)
|
|
public
|
|
{
|
|
vm.assume(governanceChainId != wormholeSimulator.governanceChainId());
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
governanceChainId,
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
action,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked("Mission accomplished.")
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid governance chain");
|
|
circleIntegration.verifyGovernanceMessage(encodedMessage, action);
|
|
}
|
|
|
|
function testCannotConsumeGovernanceMessageInvalidGovernanceContract(bytes32 governanceContract, uint8 action)
|
|
public
|
|
{
|
|
vm.assume(governanceContract != wormholeSimulator.governanceContract());
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
governanceContract,
|
|
GOVERNANCE_MODULE,
|
|
action,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked("Mission accomplished.")
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid governance contract");
|
|
circleIntegration.verifyGovernanceMessage(encodedMessage, action);
|
|
}
|
|
|
|
function testCannotConsumeGovernanceMessageInvalidModule(bytes32 governanceModule, uint8 action) public {
|
|
vm.assume(governanceModule != GOVERNANCE_MODULE);
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
governanceModule,
|
|
action,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked("Mission accomplished.")
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid governance module");
|
|
circleIntegration.verifyGovernanceMessage(encodedMessage, action);
|
|
}
|
|
|
|
function testCannotConsumeGovernanceMessageInvalidAction(uint8 action, uint8 wrongAction) public {
|
|
vm.assume(action != wrongAction);
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
action,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked("Mission accomplished.")
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid governance action");
|
|
circleIntegration.verifyGovernanceMessage(encodedMessage, wrongAction);
|
|
}
|
|
|
|
function testCannotUpdateWormholeFinalityInvalidLength(uint8 finality) public {
|
|
vm.assume(finality > 0 && finality != circleIntegration.wormholeFinality());
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_UPDATE_WORMHOLE_FINALITY,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(finality, "But wait! There's more.")
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid governance payload length");
|
|
circleIntegration.updateWormholeFinality(encodedMessage);
|
|
}
|
|
|
|
function testCannotUpdateWormholeFinalityInvalidTargetChain(uint16 targetChainId, uint8 finality) public {
|
|
vm.assume(targetChainId != circleIntegration.chainId());
|
|
vm.assume(finality > 0 && finality != circleIntegration.wormholeFinality());
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_UPDATE_WORMHOLE_FINALITY,
|
|
targetChainId,
|
|
abi.encodePacked(finality)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid target chain");
|
|
circleIntegration.updateWormholeFinality(encodedMessage);
|
|
}
|
|
|
|
function testUpdateWormholeFinality(uint8 finality) public {
|
|
vm.assume(finality > 0 && finality != circleIntegration.wormholeFinality());
|
|
|
|
assertEq(circleIntegration.wormholeFinality(), 1, "starting finality incorrect");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_UPDATE_WORMHOLE_FINALITY,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(finality)
|
|
);
|
|
|
|
// Update with governance message
|
|
circleIntegration.updateWormholeFinality(encodedMessage);
|
|
|
|
assertEq(circleIntegration.wormholeFinality(), finality, "new finality incorrect");
|
|
}
|
|
|
|
function testCannotRegisterEmitterAndDomainInvalidLength(uint16 foreignChain, bytes32 foreignEmitter, uint32 domain)
|
|
public
|
|
{
|
|
vm.assume(foreignChain > 0);
|
|
vm.assume(foreignChain != circleIntegration.chainId());
|
|
vm.assume(foreignEmitter != bytes32(0));
|
|
// For the purposes of this test, we will assume the domain set is > 0
|
|
vm.assume(domain > 0);
|
|
vm.assume(domain != circleIntegration.localDomain());
|
|
|
|
// No emitters should be registered for this chain.
|
|
assertEq(circleIntegration.getRegisteredEmitter(foreignChain), bytes32(0), "already registered");
|
|
assertEq(circleIntegration.getDomainFromChainId(foreignChain), 0, "domain already registered");
|
|
assertEq(circleIntegration.getChainIdFromDomain(domain), 0, "chain already registered");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_EMITTER_AND_DOMAIN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(foreignChain, foreignEmitter, domain, "But wait! There's more.")
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid governance payload length");
|
|
circleIntegration.registerEmitterAndDomain(encodedMessage);
|
|
}
|
|
|
|
function testCannotRegisterEmitterAndDomainInvalidTargetChain(
|
|
uint16 targetChain,
|
|
uint16 foreignChain,
|
|
bytes32 foreignEmitter,
|
|
uint32 domain
|
|
) public {
|
|
vm.assume(targetChain != circleIntegration.chainId());
|
|
vm.assume(foreignChain > 0);
|
|
vm.assume(foreignChain != circleIntegration.chainId());
|
|
vm.assume(foreignEmitter != bytes32(0));
|
|
// For the purposes of this test, we will assume the domain set is > 0
|
|
vm.assume(domain > 0);
|
|
vm.assume(domain != circleIntegration.localDomain());
|
|
|
|
// No emitters should be registered for this chain.
|
|
assertEq(circleIntegration.getRegisteredEmitter(foreignChain), bytes32(0), "already registered");
|
|
assertEq(circleIntegration.getDomainFromChainId(foreignChain), 0, "domain already registered");
|
|
assertEq(circleIntegration.getChainIdFromDomain(domain), 0, "chain already registered");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_EMITTER_AND_DOMAIN,
|
|
targetChain,
|
|
abi.encodePacked(foreignChain, foreignEmitter, domain)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid target chain");
|
|
circleIntegration.registerEmitterAndDomain(encodedMessage);
|
|
}
|
|
|
|
function testCannotRegisterEmitterAndDomainInvalidForeignChain(bytes32 foreignEmitter, uint32 domain) public {
|
|
vm.assume(foreignEmitter != bytes32(0));
|
|
// For the purposes of this test, we will assume the domain set is > 0
|
|
vm.assume(domain > 0);
|
|
vm.assume(domain != circleIntegration.localDomain());
|
|
|
|
// No emitters should be registered for this chain.
|
|
|
|
// emitterChain cannot be zero
|
|
{
|
|
uint16 foreignChain = 0;
|
|
assertEq(circleIntegration.getRegisteredEmitter(foreignChain), bytes32(0), "already registered");
|
|
assertEq(circleIntegration.getDomainFromChainId(foreignChain), 0, "domain already registered");
|
|
assertEq(circleIntegration.getChainIdFromDomain(domain), 0, "chain already registered");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_EMITTER_AND_DOMAIN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(foreignChain, foreignEmitter, domain)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid chain");
|
|
circleIntegration.registerEmitterAndDomain(encodedMessage);
|
|
}
|
|
|
|
// emitterChain cannot be this chain's
|
|
{
|
|
uint16 foreignChain = circleIntegration.chainId();
|
|
assertEq(circleIntegration.getRegisteredEmitter(foreignChain), bytes32(0), "already registered");
|
|
assertEq(circleIntegration.getDomainFromChainId(foreignChain), 0, "domain already registered");
|
|
assertEq(circleIntegration.getChainIdFromDomain(domain), 0, "chain already registered");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_EMITTER_AND_DOMAIN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(foreignChain, foreignEmitter, domain)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid chain");
|
|
circleIntegration.registerEmitterAndDomain(encodedMessage);
|
|
}
|
|
}
|
|
|
|
function testCannotRegisterEmitterAndDomainInvalidEmitterAddress(uint16 foreignChain, uint32 domain) public {
|
|
vm.assume(foreignChain > 0);
|
|
vm.assume(foreignChain != circleIntegration.chainId());
|
|
// For the purposes of this test, we will assume the domain set is > 0
|
|
vm.assume(domain > 0);
|
|
vm.assume(domain != circleIntegration.localDomain());
|
|
|
|
// No emitters should be registered for this chain.
|
|
assertEq(circleIntegration.getRegisteredEmitter(foreignChain), bytes32(0), "already registered");
|
|
assertEq(circleIntegration.getDomainFromChainId(foreignChain), 0, "domain already registered");
|
|
assertEq(circleIntegration.getChainIdFromDomain(domain), 0, "chain already registered");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_EMITTER_AND_DOMAIN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(
|
|
foreignChain,
|
|
bytes32(0), // emitterAddress
|
|
domain
|
|
)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("emitter cannot be zero address");
|
|
circleIntegration.registerEmitterAndDomain(encodedMessage);
|
|
}
|
|
|
|
function testCannotRegisterEmitterAndDomainInvalidDomain(uint16 foreignChain, bytes32 foreignEmitter) public {
|
|
vm.assume(foreignChain > 0);
|
|
vm.assume(foreignChain != circleIntegration.chainId());
|
|
vm.assume(foreignEmitter != bytes32(0));
|
|
|
|
// No emitters should be registered for this chain.
|
|
assertEq(circleIntegration.getRegisteredEmitter(foreignChain), bytes32(0), "already registered");
|
|
assertEq(circleIntegration.getDomainFromChainId(foreignChain), 0, "domain already registered");
|
|
|
|
{
|
|
uint32 domain = circleIntegration.localDomain();
|
|
assertEq(circleIntegration.getChainIdFromDomain(domain), 0, "chain already registered");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_EMITTER_AND_DOMAIN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(foreignChain, foreignEmitter, domain)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("domain == localDomain()");
|
|
circleIntegration.registerEmitterAndDomain(encodedMessage);
|
|
}
|
|
}
|
|
|
|
function testRegisterEmitterAndDomain(uint16 foreignChain, bytes32 foreignEmitter, uint32 domain) public {
|
|
vm.assume(foreignChain > 0);
|
|
vm.assume(foreignChain != circleIntegration.chainId());
|
|
vm.assume(foreignEmitter != bytes32(0));
|
|
// For the purposes of this test, we will assume the domain set is > 0
|
|
vm.assume(domain > 0);
|
|
vm.assume(domain != circleIntegration.localDomain());
|
|
|
|
// No emitters should be registered for this chain.
|
|
assertEq(circleIntegration.getRegisteredEmitter(foreignChain), bytes32(0), "already registered");
|
|
assertEq(circleIntegration.getDomainFromChainId(foreignChain), 0, "domain already registered");
|
|
assertEq(circleIntegration.getChainIdFromDomain(domain), 0, "chain already registered");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_EMITTER_AND_DOMAIN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(foreignChain, foreignEmitter, domain)
|
|
);
|
|
|
|
// Register emitter and domain.
|
|
circleIntegration.registerEmitterAndDomain(encodedMessage);
|
|
|
|
require(circleIntegration.getRegisteredEmitter(foreignChain) == foreignEmitter, "wrong foreignEmitter");
|
|
require(circleIntegration.getDomainFromChainId(foreignChain) == domain, "wrong domain");
|
|
require(circleIntegration.getChainIdFromDomain(domain) == foreignChain, "wrong chain");
|
|
|
|
// we cannot register for this chain again
|
|
{
|
|
bytes memory anotherMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_EMITTER_AND_DOMAIN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(foreignChain, foreignEmitter, domain)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("chain already registered");
|
|
circleIntegration.registerEmitterAndDomain(anotherMessage);
|
|
}
|
|
}
|
|
|
|
function testCannotRegisterTargetChainTokenInvalidLength(
|
|
address sourceToken,
|
|
uint16 targetChain,
|
|
bytes32 targetToken
|
|
) public {
|
|
vm.assume(sourceToken != address(0));
|
|
vm.assume(targetChain > 0 && targetChain != circleIntegration.chainId());
|
|
vm.assume(targetToken != bytes32(0));
|
|
|
|
// First register source token
|
|
registerToken(sourceToken);
|
|
|
|
// Should not already exist.
|
|
assertEq(
|
|
circleIntegration.targetAcceptedToken(sourceToken, targetChain),
|
|
bytes32(0),
|
|
"target token already registered"
|
|
);
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_TARGET_CHAIN_TOKEN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(bytes12(0), sourceToken, targetChain, targetToken, "But wait! There's more.")
|
|
);
|
|
|
|
// Now register target token.
|
|
vm.expectRevert("invalid governance payload length");
|
|
circleIntegration.registerTargetChainToken(encodedMessage);
|
|
}
|
|
|
|
function testCannotRegisterAcceptedTokenInvalidLength(address tokenAddress) public {
|
|
vm.assume(tokenAddress != address(0));
|
|
|
|
// Should not already be accepted.
|
|
assertTrue(!circleIntegration.isAcceptedToken(tokenAddress), "token already registered");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_ACCEPTED_TOKEN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(bytes12(0), tokenAddress, "But wait! There's more.")
|
|
);
|
|
|
|
// Register and should now be accepted.
|
|
vm.expectRevert("invalid governance payload length");
|
|
circleIntegration.registerAcceptedToken(encodedMessage);
|
|
}
|
|
|
|
function testCannotRegisterAcceptedTokenZeroAddress() public {
|
|
// Should not already be accepted.
|
|
address tokenAddress = address(0);
|
|
assertTrue(!circleIntegration.isAcceptedToken(tokenAddress), "token already registered");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_ACCEPTED_TOKEN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(bytes12(0), tokenAddress)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("token is zero address");
|
|
circleIntegration.registerAcceptedToken(encodedMessage);
|
|
}
|
|
|
|
function testCannotRegisterAcceptedTokenInvalidToken(bytes12 garbage, address tokenAddress) public {
|
|
vm.assume(garbage != bytes12(0));
|
|
vm.assume(tokenAddress != address(0));
|
|
|
|
// Should not already be accepted.
|
|
assertTrue(!circleIntegration.isAcceptedToken(tokenAddress), "token already registered");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_ACCEPTED_TOKEN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(garbage, tokenAddress)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid address");
|
|
circleIntegration.registerAcceptedToken(encodedMessage);
|
|
}
|
|
|
|
function testRegisterAcceptedToken(address tokenAddress) public {
|
|
vm.assume(tokenAddress != address(0));
|
|
|
|
// Should not already be accepted.
|
|
assertTrue(!circleIntegration.isAcceptedToken(tokenAddress), "token already registered");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_ACCEPTED_TOKEN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(bytes12(0), tokenAddress)
|
|
);
|
|
|
|
// Register and should now be accepted.
|
|
circleIntegration.registerAcceptedToken(encodedMessage);
|
|
|
|
assertTrue(circleIntegration.isAcceptedToken(tokenAddress), "token not registered");
|
|
}
|
|
|
|
function testCannotRegisterTargetChainTokenInvalidSourceToken(
|
|
bytes12 garbage,
|
|
address sourceToken,
|
|
uint16 targetChain,
|
|
bytes32 targetToken
|
|
) public {
|
|
vm.assume(garbage != bytes12(0));
|
|
vm.assume(sourceToken != address(0));
|
|
vm.assume(targetChain > 0 && targetChain != circleIntegration.chainId());
|
|
vm.assume(targetToken != bytes32(0));
|
|
|
|
// Should not already exist.
|
|
assertEq(
|
|
circleIntegration.targetAcceptedToken(sourceToken, targetChain),
|
|
bytes32(0),
|
|
"target token already registered"
|
|
);
|
|
|
|
// First attempt to submit garbage source token
|
|
{
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_TARGET_CHAIN_TOKEN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(garbage, sourceToken, targetChain, targetToken)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid address");
|
|
circleIntegration.registerTargetChainToken(encodedMessage);
|
|
}
|
|
|
|
// Now use legitimate-looking ERC20 address
|
|
{
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_TARGET_CHAIN_TOKEN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(bytes12(0), sourceToken, targetChain, targetToken)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("source token not accepted");
|
|
circleIntegration.registerTargetChainToken(encodedMessage);
|
|
}
|
|
}
|
|
|
|
function testCannotRegisterTargetChainTokenInvalidTargetChain(address sourceToken, bytes32 targetToken) public {
|
|
vm.assume(sourceToken != address(0));
|
|
vm.assume(targetToken != bytes32(0));
|
|
|
|
// First register source token
|
|
registerToken(sourceToken);
|
|
|
|
// Cannot register chain ID == 0
|
|
{
|
|
uint16 targetChain = 0;
|
|
|
|
// Should not already exist.
|
|
assertEq(
|
|
circleIntegration.targetAcceptedToken(sourceToken, targetChain),
|
|
bytes32(0),
|
|
"target token already registered"
|
|
);
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_TARGET_CHAIN_TOKEN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(bytes12(0), sourceToken, targetChain, targetToken)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid target chain");
|
|
circleIntegration.registerTargetChainToken(encodedMessage);
|
|
}
|
|
|
|
// Cannot register chain ID == this chain's
|
|
{
|
|
uint16 targetChain = circleIntegration.chainId();
|
|
|
|
// Should not already exist.
|
|
assertEq(
|
|
circleIntegration.targetAcceptedToken(sourceToken, targetChain),
|
|
bytes32(0),
|
|
"target token already registered"
|
|
);
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_TARGET_CHAIN_TOKEN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(bytes12(0), sourceToken, targetChain, targetToken)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid target chain");
|
|
circleIntegration.registerTargetChainToken(encodedMessage);
|
|
}
|
|
}
|
|
|
|
function testCannotRegisterTargetChainTokenInvalidTargetToken(address sourceToken, uint16 targetChain) public {
|
|
vm.assume(sourceToken != address(0));
|
|
vm.assume(targetChain > 0 && targetChain != circleIntegration.chainId());
|
|
|
|
// First register source token
|
|
registerToken(sourceToken);
|
|
|
|
// Should not already exist.
|
|
assertEq(
|
|
circleIntegration.targetAcceptedToken(sourceToken, targetChain),
|
|
bytes32(0),
|
|
"target token already registered"
|
|
);
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_TARGET_CHAIN_TOKEN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(
|
|
bytes12(0),
|
|
sourceToken,
|
|
targetChain,
|
|
bytes32(0) // targetToken
|
|
)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("target token is zero address");
|
|
circleIntegration.registerTargetChainToken(encodedMessage);
|
|
}
|
|
|
|
function testRegisterTargetChainToken(address sourceToken, uint16 targetChain, bytes32 targetToken) public {
|
|
vm.assume(sourceToken != address(0));
|
|
vm.assume(targetChain > 0 && targetChain != circleIntegration.chainId());
|
|
vm.assume(targetToken != bytes32(0));
|
|
|
|
// First register source token
|
|
registerToken(sourceToken);
|
|
|
|
// Should not already exist.
|
|
assertEq(
|
|
circleIntegration.targetAcceptedToken(sourceToken, targetChain),
|
|
bytes32(0),
|
|
"target token already registered"
|
|
);
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_REGISTER_TARGET_CHAIN_TOKEN,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(bytes12(0), sourceToken, targetChain, targetToken)
|
|
);
|
|
|
|
// Now register target token.
|
|
circleIntegration.registerTargetChainToken(encodedMessage);
|
|
assertEq(
|
|
circleIntegration.targetAcceptedToken(sourceToken, targetChain), targetToken, "target token not registered"
|
|
);
|
|
}
|
|
|
|
function testCannotUpgradeContractInvalidImplementation(bytes12 garbage, address newImplementation) public {
|
|
vm.assume(garbage != bytes12(0));
|
|
vm.assume(newImplementation != address(0) && !circleIntegration.isInitialized(newImplementation));
|
|
|
|
// First attempt to submit garbage implementation
|
|
{
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_UPGRADE_CONTRACT,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(garbage, newImplementation)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid address");
|
|
circleIntegration.upgradeContract(encodedMessage);
|
|
}
|
|
|
|
// Now use legitimate-looking ERC20 address
|
|
{
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_UPGRADE_CONTRACT,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(bytes12(0), newImplementation)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid implementation");
|
|
circleIntegration.upgradeContract(encodedMessage);
|
|
}
|
|
|
|
// Now use one of Wormhole's implementations
|
|
{
|
|
address wormholeImplementation = 0x46DB25598441915D59df8955DD2E4256bC3c6e95;
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_UPGRADE_CONTRACT,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(bytes12(0), wormholeImplementation)
|
|
);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid implementation");
|
|
circleIntegration.upgradeContract(encodedMessage);
|
|
}
|
|
}
|
|
|
|
function testUpgradeContract() public {
|
|
// Deploy new implementation.
|
|
CircleIntegrationImplementation implementation = new CircleIntegrationImplementation();
|
|
|
|
// Should not be initialized yet.
|
|
require(!circleIntegration.isInitialized(address(implementation)), "already initialized");
|
|
|
|
bytes memory encodedMessage = wormholeSimulator.makeSignedGovernanceObservation(
|
|
wormholeSimulator.governanceChainId(),
|
|
wormholeSimulator.governanceContract(),
|
|
GOVERNANCE_MODULE,
|
|
GOVERNANCE_UPGRADE_CONTRACT,
|
|
circleIntegration.chainId(),
|
|
abi.encodePacked(bytes12(0), address(implementation))
|
|
);
|
|
|
|
// Upgrade contract.
|
|
circleIntegration.upgradeContract(encodedMessage);
|
|
|
|
// Should not be initialized yet.
|
|
require(circleIntegration.isInitialized(address(implementation)), "implementation not initialized");
|
|
}
|
|
|
|
function testCannotTransferTokensWithPayloadInvalidToken(
|
|
address token,
|
|
uint256 amount,
|
|
uint16 targetChain,
|
|
bytes32 mintRecipient
|
|
) public {
|
|
vm.assume(token != address(usdc));
|
|
vm.assume(amount > 0 && amount <= maxUSDCAmountToMint());
|
|
vm.assume(targetChain > 0 && targetChain != circleIntegration.chainId());
|
|
vm.assume(mintRecipient != bytes32(0));
|
|
|
|
prepareCircleIntegrationTest(amount);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("token not accepted");
|
|
circleIntegration.transferTokensWithPayload(
|
|
ICircleIntegration.TransferParameters({
|
|
token: token,
|
|
amount: amount,
|
|
targetChain: targetChain,
|
|
mintRecipient: mintRecipient
|
|
}),
|
|
0, // batchId
|
|
abi.encodePacked("All your base are belong to us") // payload
|
|
);
|
|
}
|
|
|
|
function testCannotTransferTokensWithPayloadZeroAmount(uint16 targetChain, bytes32 mintRecipient) public {
|
|
vm.assume(targetChain > 0 && targetChain != circleIntegration.chainId());
|
|
vm.assume(mintRecipient != bytes32(0));
|
|
|
|
uint256 amount = 0;
|
|
prepareCircleIntegrationTest(amount);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("amount must be > 0");
|
|
circleIntegration.transferTokensWithPayload(
|
|
ICircleIntegration.TransferParameters({
|
|
token: address(usdc),
|
|
amount: amount,
|
|
targetChain: targetChain,
|
|
mintRecipient: mintRecipient
|
|
}),
|
|
0, // batchId
|
|
abi.encodePacked("All your base are belong to us") // payload
|
|
);
|
|
}
|
|
|
|
function testCannotTransferTokensWithPayloadInvalidMintRecipient(uint256 amount, uint16 targetChain) public {
|
|
vm.assume(amount > 0 && amount <= maxUSDCAmountToMint());
|
|
vm.assume(targetChain > 0 && targetChain != circleIntegration.chainId());
|
|
|
|
prepareCircleIntegrationTest(amount);
|
|
|
|
// You shall not pass!
|
|
vm.expectRevert("invalid mint recipient");
|
|
circleIntegration.transferTokensWithPayload(
|
|
ICircleIntegration.TransferParameters({
|
|
token: address(usdc),
|
|
amount: amount,
|
|
targetChain: targetChain,
|
|
mintRecipient: bytes32(0)
|
|
}),
|
|
0, // batchId
|
|
abi.encodePacked("All your base are belong to us") // payload
|
|
);
|
|
}
|
|
|
|
// function testTransferTokensWithPayload(uint256 amount, uint16 targetChain, bytes32 mintRecipient) public {
|
|
// vm.assume(amount > 0 && amount <= maxUSDCAmountToMint());
|
|
// vm.assume(targetChain > 0 && targetChain != circleIntegration.chainId());
|
|
// vm.assume(mintRecipient != bytes32(0));
|
|
|
|
// registerContract(
|
|
// targetChain,
|
|
// 0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef, // foreignEmitter
|
|
// 1 // domain
|
|
// );
|
|
|
|
// prepareCircleIntegrationTest(amount);
|
|
|
|
// // Register target token
|
|
// circleIntegration.registerTargetChainToken(
|
|
// address(usdc), // sourceToken
|
|
// targetChain,
|
|
// foreignUsdc // targetToken
|
|
// );
|
|
|
|
// // Record balance.
|
|
// uint256 myBalanceBefore = usdc.balanceOf(address(this));
|
|
// assertEq(usdc.balanceOf(address(circleIntegration)), 0, "CircleIntegration has balance");
|
|
|
|
// bytes memory payload = abi.encodePacked("All your base are belong to us");
|
|
|
|
// vm.recordLogs();
|
|
|
|
// // Pass.
|
|
// circleIntegration.transferTokensWithPayload(address(usdc), amount, targetChain, mintRecipient, payload);
|
|
|
|
// // Prepare to check transaction logs for expected events.
|
|
// Vm.Log[] memory entries = vm.getRecordedLogs();
|
|
|
|
// // Circle's MessageSent value
|
|
// bytes memory message = circleSimulator.findMessageSentInLogs(entries);
|
|
|
|
// // Wormhole's LogMessagePublished values
|
|
// (uint64 sequence, uint32 batchId, bytes memory wormholePayload, uint8 finality) =
|
|
// wormholeSimulator.findLogMessagePublishedInLogs(entries);
|
|
// assertEq(sequence, 0, "sequence != expected");
|
|
// assertEq(batchId, 0, "batchId != expected");
|
|
// assertEq(finality, circleIntegration.wormholeFinality(), "finality != circleIntegration.wormholeFinality()");
|
|
|
|
// // Deserialize wormhole payload
|
|
// CircleIntegrationSimulator.DepositWithPayload memory deposit =
|
|
// circleSimulator.decodeDepositWithPayload(wormholePayload);
|
|
// assertEq(
|
|
// deposit.token,
|
|
// circleIntegration.targetAcceptedToken(address(usdc), targetChain),
|
|
// "deposit.token != expected"
|
|
// );
|
|
// assertEq(deposit.amount, amount, "deposit.amount != expected");
|
|
// assertEq(deposit.sourceDomain, circleIntegration.localDomain(), "deposit.sourceDomain != expected");
|
|
// assertEq(
|
|
// deposit.targetDomain,
|
|
// circleIntegration.getDomainFromChainId(targetChain),
|
|
// "deposit.targetDomain != expected"
|
|
// );
|
|
// assertEq(deposit.nonce, 112396, "deposit.nonce != expected");
|
|
// assertEq(deposit.mintRecipient, mintRecipient, "deposit.mintRecipient != expected");
|
|
// assertEq(deposit.payload, payload, "deposit.payload != expected");
|
|
|
|
// // My balance change should equal the amount transferred.
|
|
// assertEq(myBalanceBefore - usdc.balanceOf(address(this)), amount, "mismatch in my balance");
|
|
|
|
// // CircleIntegration's balance should not reflect having any USDC.
|
|
// assertEq(usdc.balanceOf(address(circleIntegration)), 0, "CircleIntegration has new balance");
|
|
// }
|
|
|
|
// function borkedTestRedeemTokensWithPayload(uint16 foreignChain) public {
|
|
// vm.assume(foreignChain > 0 && foreignChain != circleIntegration.chainId());
|
|
|
|
// uint32 foreignDomain = 1;
|
|
// // Register foreign CircleIntegration
|
|
// registerContract(
|
|
// foreignChain,
|
|
// bytes32(uint256(uint160(address(circleIntegration)))), // foreignEmitter
|
|
// foreignDomain // domain
|
|
// );
|
|
|
|
// uint256 amount = 42069;
|
|
// uint64 availableNonce = uint64(vm.envUint("TESTING_LAST_NONCE"));
|
|
|
|
// ICircleIntegration.RedeemParameters memory redeemParams;
|
|
|
|
// redeemParams.circleBridgeMessage = abi.encodePacked(
|
|
// messageTransmitter.version(),
|
|
// foreignDomain,
|
|
// circleIntegration.localDomain(),
|
|
// availableNonce,
|
|
// circleBridge.remoteCircleBridges(foreignDomain),
|
|
// bytes32(uint256(uint160(address(circleBridge)))),
|
|
// circleIntegration.getRegisteredEmitter(foreignChain), // expected caller
|
|
// bytes4(0), // ???
|
|
// foreignUsdc,
|
|
// bytes32(uint256(uint160(address(this)))), // attester
|
|
// amount
|
|
// );
|
|
// redeemParams.circleAttestation = circleSimulator.attestMessage(redeemParams.circleBridgeMessage);
|
|
|
|
// IWormhole.VM memory wormholeMessage;
|
|
// wormholeMessage.timestamp = uint32(block.timestamp);
|
|
// wormholeMessage.nonce = 0;
|
|
// wormholeMessage.emitterChainId = foreignChain;
|
|
// wormholeMessage.emitterAddress = bytes32(uint256(uint160(address(circleIntegration))));
|
|
// wormholeMessage.sequence = 0;
|
|
// wormholeMessage.consistencyLevel = 1;
|
|
// wormholeMessage.payload = circleSimulator.encodeDepositWithPayload(
|
|
// CircleIntegrationStructs.DepositWithPayload({
|
|
// token: foreignUsdc,
|
|
// amount: amount,
|
|
// sourceDomain: foreignDomain,
|
|
// targetDomain: circleIntegration.localDomain(),
|
|
// nonce: availableNonce,
|
|
// fromAddress: bytes32(uint256(uint160(address(this)))),
|
|
// mintRecipient: bytes32(uint256(uint160(address(this)))),
|
|
// payload: abi.encodePacked("All your base are belong to us")
|
|
// })
|
|
// );
|
|
// redeemParams.encodedWormholeMessage = wormholeSimulator.signDevnetObservation(wormholeMessage);
|
|
|
|
// circleIntegration.redeemTokensWithPayload(redeemParams);
|
|
// }
|
|
}
|