Created
August 28, 2025 06:06
-
-
Save 0xvangrim/f3e8b0675bc48c29038e0ea080619e75 to your computer and use it in GitHub Desktop.
POC issue #611 for Malda
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // SPDX-License-Identifier: BSL-1.1 | |
| pragma solidity =0.8.28; | |
| // tests | |
| import {mToken_Unit_Shared} from "../shared/mToken_Unit_Shared.t.sol"; | |
| import {ImTokenOperationTypes} from "src/interfaces/ImToken.sol"; | |
| contract mErc20Host_ProofEnvChainSpec_DoS is mToken_Unit_Shared { | |
| function setUp() public virtual override { | |
| super.setUp(); | |
| // Allow foreign chain (Ethereum mainnet = 1) as a valid source | |
| mWethHost.updateAllowedChain(1, true); | |
| } | |
| function _buildJournal( | |
| address sender, | |
| address market, | |
| uint256 accAmountIn, | |
| uint256 accAmountOut, | |
| uint32 srcChainId, | |
| uint32 dstChainId, | |
| bool l1Inclusion | |
| ) internal pure returns (bytes memory) { | |
| // | Offset | Length | Data Type | | |
| // | 0 | 20 | address sender | | |
| // | 20 | 20 | address market | | |
| // | 40 | 32 | uint256 accAmountIn | | |
| // | 72 | 32 | uint256 accAmountOut | | |
| // | 104 | 4 | uint32 chainId | | |
| // | 108 | 4 | uint32 dstChainId | | |
| // | 112 | 1 | bool L1inclusion | | |
| bytes memory single = abi.encodePacked( | |
| sender, | |
| market, | |
| accAmountIn, | |
| accAmountOut, | |
| srcChainId, | |
| dstChainId, | |
| l1Inclusion | |
| ); | |
| bytes[] memory arr = new bytes[](1); | |
| arr[0] = single; | |
| return abi.encode(arr); | |
| } | |
| // 1) With a foreign chainId, a bad proof (e.g., due to wrong ChainSpec) reverts at verifier → DoS | |
| function test_EthereumChainId_InvalidProof_Reverts_mintExternal() | |
| external | |
| whenMarketIsListed(address(mWethHost)) | |
| whenNotPaused(address(mWethHost), ImTokenOperationTypes.OperationType.Mint) | |
| { | |
| address user = address(this); | |
| uint32 srcChainId = 1; // Ethereum mainnet | |
| uint32 dstChainId = uint32(block.chainid); // Linea host | |
| uint256 mintAmt = 1_000e18; | |
| bytes memory journalData = _buildJournal(user, address(mWethHost), mintAmt, mintAmt, srcChainId, dstChainId, true); | |
| uint256[] memory amounts = new uint256[](1); | |
| amounts[0] = mintAmt; | |
| uint256[] memory minOut = new uint256[](1); | |
| minOut[0] = 0; | |
| // Simulate invalid proof from backend (e.g., built with wrong ChainSpec) | |
| verifierMock.setStatus(true); | |
| // Expect revert inside verifier.verifyInput → host call DoS | |
| vm.expectRevert(); | |
| mWethHost.mintExternal(journalData, bytes(""), amounts, minOut, user); | |
| } | |
| // 2) Same request with verifier accepting the proof succeeds and updates acc inPerChain | |
| function test_EthereumChainId_ValidProof_Succeeds_mintExternal() | |
| external | |
| whenMarketIsListed(address(mWethHost)) | |
| whenNotPaused(address(mWethHost), ImTokenOperationTypes.OperationType.Mint) | |
| { | |
| address user = address(this); | |
| uint32 srcChainId = 1; // Ethereum mainnet | |
| uint32 dstChainId = uint32(block.chainid); // Linea host | |
| uint256 mintAmt = 500e18; | |
| // Before: no inflow recorded (indexed by source chain id) | |
| (uint256 inBefore, uint256 outBefore) = mWethHost.getProofData(user, srcChainId); | |
| assertEq(inBefore, 0); | |
| assertEq(outBefore, 0); | |
| bytes memory journalData = _buildJournal(user, address(mWethHost), mintAmt, mintAmt, srcChainId, dstChainId, true); | |
| uint256[] memory amounts = new uint256[](1); | |
| amounts[0] = mintAmt; | |
| uint256[] memory minOut = new uint256[](1); | |
| minOut[0] = 0; | |
| // Simulate valid proof | |
| verifierMock.setStatus(false); | |
| mWethHost.mintExternal(journalData, bytes(""), amounts, minOut, user); | |
| // After: inflow for srcChainId is recorded for user | |
| (uint256 inAfter, uint256 outAfter) = mWethHost.getProofData(user, srcChainId); | |
| assertEq(inAfter, mintAmt); | |
| assertEq(outAfter, 0); | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment