// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; import {IRouterClient} from "../../contracts/ccip/IRouterClient.sol"; import {OfficialStableMirrorToken} from "../../contracts/tokens/OfficialStableMirrorToken.sol"; import {CompliantUSDT} from "../../contracts/tokens/CompliantUSDT.sol"; import {CompliantUSDC} from "../../contracts/tokens/CompliantUSDC.sol"; import {StablecoinReserveVault} from "../../contracts/reserve/StablecoinReserveVault.sol"; import {CWMultiTokenBridgeL1} from "../../contracts/bridge/CWMultiTokenBridgeL1.sol"; import {CWReserveVerifier} from "../../contracts/bridge/integration/CWReserveVerifier.sol"; contract MockRouterVaultVerifier is IRouterClient { uint256 public fee; bytes32 public nextMessageId = keccak256("cw-reserve-vault-message"); function ccipSend( uint64, EVM2AnyMessage memory ) external payable returns (bytes32 messageId, uint256 fees) { return (nextMessageId, fee); } function getFee(uint64, EVM2AnyMessage memory) external view returns (uint256) { return fee; } function getSupportedTokens(uint64) external pure returns (address[] memory tokens) { tokens = new address[](0); } } contract CWReserveVerifierVaultIntegrationTest is Test { uint64 internal constant AVALANCHE_SELECTOR = 6433500567565415381; address internal user = address(0xBEEF); address internal receiveRouter = address(0x138138); address internal peerBridge = address(0x4311443114); MockRouterVaultVerifier internal router; OfficialStableMirrorToken internal officialUsdt; OfficialStableMirrorToken internal officialUsdc; CompliantUSDT internal compliantUsdt; CompliantUSDC internal compliantUsdc; StablecoinReserveVault internal vault; CWMultiTokenBridgeL1 internal l1Bridge; CWReserveVerifier internal verifier; function setUp() public { router = new MockRouterVaultVerifier(); officialUsdt = new OfficialStableMirrorToken("Tether USD (Chain 138)", "USDT", 6, address(this), 0); officialUsdc = new OfficialStableMirrorToken("USD Coin (Chain 138)", "USDC", 6, address(this), 0); compliantUsdt = new CompliantUSDT(address(this), address(this)); compliantUsdc = new CompliantUSDC(address(this), address(this)); vault = new StablecoinReserveVault( address(this), address(officialUsdt), address(officialUsdc), address(compliantUsdt), address(compliantUsdc) ); l1Bridge = new CWMultiTokenBridgeL1(address(router), receiveRouter, address(0)); verifier = new CWReserveVerifier(address(this), address(l1Bridge), address(vault), address(0)); uint256 canonicalSupply = compliantUsdc.totalSupply(); officialUsdc.mint(address(this), canonicalSupply); officialUsdc.approve(address(vault), canonicalSupply); vault.seedUSDCReserve(canonicalSupply); compliantUsdc.transferOwnership(address(vault)); compliantUsdc.transfer(user, 250e6); l1Bridge.configureSupportedCanonicalToken(address(compliantUsdc), true); l1Bridge.configureDestination(address(compliantUsdc), AVALANCHE_SELECTOR, peerBridge, true); l1Bridge.setReserveVerifier(address(verifier)); verifier.configureToken( address(compliantUsdc), address(0), true, false, true ); } function testVerifierAllowsLockWhenRealVaultBacksExistingSupply() public { uint256 amount = 25e6; vm.startPrank(user); compliantUsdc.approve(address(l1Bridge), amount); l1Bridge.lockAndSend(address(compliantUsdc), AVALANCHE_SELECTOR, user, amount); vm.stopPrank(); assertEq(l1Bridge.lockedBalance(address(compliantUsdc)), amount); assertEq(l1Bridge.totalOutstanding(address(compliantUsdc)), amount); assertEq(l1Bridge.outstandingMinted(address(compliantUsdc), AVALANCHE_SELECTOR), amount); } }