// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {Assertion} from "../lib/credible-std/Assertion.sol";
// VestraDAO interface
interface IVestraDAO {
struct Stake {
uint64 startTime;
uint256 stakeAmount;
uint256 yield;
uint256 penalty;
uint64 endTime;
bool isActive;
}
mapping(address => mapping(uint8 => Stake)) public stakes;
function unStake(uint8 maturity) external;
}
contract VestraDAOHack is Assertion {
IVestraDAO public vestraDAO = IVestraDAO(address(0xbeef));
function triggers() external view override {
registerCallTrigger(this.assertionExample.selector, vestraDAO.unStake.selector);
}
// Check that user was actively staked before unstaking
// This prevents double-unstaking by ensuring isActive was true before the call
function assertionExample() external view {
PhEvm.CallInputs[] memory unStakes = ph.getCallInputs(address(vestraDAO), vestraDAO.unStake.selector);
for (uint256 i = 0; i < unStakes.length; i++) {
uint8 maturity = abi.decode(unStakes[i].input, (uint8));
address from = unStakes[i].caller;
// Check BEFORE the unstake that the stake was active
ph.forkPreCall(unStakes[i].id);
(,,,,,bool wasActive) = vestraDAO.stakes(from, maturity);
require(wasActive, "User was not actively staked for this maturity");
}
}
}