Merge pull request 'fix: fix: Debug failing staking-safe attack in evolution fitness (#596)' (#598) from fix/issue-596 into master

This commit is contained in:
johba 2026-03-12 08:43:53 +01:00
commit bd291bc9b9

View file

@ -50,7 +50,7 @@ interface IOptimizer {
interface IStake {
// taxRate matches the actual Stake.sol parameter name (a raw rate value, not a lookup index)
function snatch(uint256 assets, address receiver, uint32 taxRate, uint256[] calldata positionsToSnatch) external;
function snatch(uint256 assets, address receiver, uint32 taxRate, uint256[] calldata positionsToSnatch) external returns (uint256 positionId);
function exitPosition(uint256 positionId) external;
}
@ -169,6 +169,9 @@ contract AttackRunner is Script {
address internal optAddr;
IUniswapV3Pool internal pool;
bool internal token0isWeth;
/// @dev On-chain position IDs returned by Stake.snatch(), in insertion order.
/// Attack files reference positions by 1-based index (positionId=1 _stakedPositionIds[0]).
uint256[] internal _stakedPositionIds;
/// @dev Direction of the most recent recenter: true = price moved up, false = price moved down.
/// Read by _logSnapshot to include in post-recenter snapshots.
bool internal _lastRecenterIsUp;
@ -313,19 +316,29 @@ contract AttackRunner is Script {
/// @dev Stake KRK via Stake.snatch() with no snatching.
/// Attack files use the field key ".taxRateIndex" for backward compatibility;
/// the value is passed directly as a raw taxRate to Stake.snatch().
/// The returned positionId is appended to _stakedPositionIds so that
/// subsequent unstake ops can reference positions by 1-based index.
function _executeStake(string memory line) internal {
uint256 amount = vm.parseUint(vm.parseJsonString(line, ".amount"));
uint32 taxRate = uint32(vm.parseJsonUint(line, ".taxRateIndex")); // JSONL key kept for compat
vm.startBroadcast(ADV_PK);
IStake(stakeAddr).snatch(amount, advAddr, taxRate, new uint256[](0));
uint256 newPositionId = IStake(stakeAddr).snatch(amount, advAddr, taxRate, new uint256[](0));
vm.stopBroadcast();
_stakedPositionIds.push(newPositionId);
}
/// @dev Exit a staking position.
/// positionId in the attack file is a 1-based index into _stakedPositionIds
/// (the positions created by stake ops in this run), not the raw on-chain ID.
/// Stake.nextPositionId starts at 654_321, so literal IDs like "1" would always
/// revert with PositionNotFound the index-based lookup resolves the real ID.
function _executeUnstake(string memory line) internal {
uint256 positionId = vm.parseJsonUint(line, ".positionId");
uint256 positionIndex = vm.parseJsonUint(line, ".positionId");
require(positionIndex >= 1 && positionIndex <= _stakedPositionIds.length,
"AttackRunner: unstake positionId out of range (must be 1-based index of a prior stake op)");
uint256 realPositionId = _stakedPositionIds[positionIndex - 1];
vm.startBroadcast(ADV_PK);
IStake(stakeAddr).exitPosition(positionId);
IStake(stakeAddr).exitPosition(realPositionId);
vm.stopBroadcast();
}