Merge pull request 'fix: Attack files have hardcoded tokenIds that are fork-block-sensitive (#614)' (#1109) from fix/issue-614 into master

This commit is contained in:
johba 2026-03-22 11:34:45 +01:00
commit e22e6ac7bb

View file

@ -136,7 +136,7 @@ interface IUniswapV3Factory {
* stake Call Stake.snatch(). Fields: amount (wei string), taxRateIndex (raw taxRate value passed to Stake.snatch)
* unstake Call Stake.exitPosition(). Fields: positionId
* mint_lp Add LP via NPM. Fields: tickLower, tickUpper, amount0 (wei string), amount1 (wei string)
* burn_lp Remove LP via NPM. Fields: tokenId
* burn_lp Remove LP via NPM. Fields: positionIndex (1-based index of a prior mint_lp op)
* mine Advance block number. Fields: blocks
*
* Snapshot schema (emitted as JSON line on stdout):
@ -178,6 +178,10 @@ contract AttackRunner is Script {
/// @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 NFT token IDs returned by NPM.mint(), in insertion order.
/// Attack files reference LP positions by 1-based index (positionIndex=1 _mintedLpTokenIds[0]).
/// This makes burn_lp fork-block-independent the tokenId is resolved at runtime.
uint256[] internal _mintedLpTokenIds;
/// @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;
@ -415,7 +419,7 @@ contract AttackRunner is Script {
(address t0, address t1) = token0isWeth ? (WETH, krkAddr) : (krkAddr, WETH);
vm.startBroadcast(ADV_PK);
INonfungiblePositionManager(npmAddr).mint(
(uint256 tokenId,,,) = INonfungiblePositionManager(npmAddr).mint(
INonfungiblePositionManager.MintParams({
token0: t0,
token1: t1,
@ -431,15 +435,32 @@ contract AttackRunner is Script {
})
);
vm.stopBroadcast();
_mintedLpTokenIds.push(tokenId);
}
/// @dev Burn a Uniswap V3 LP position (decreaseLiquidity + collect).
/// positionIndex in the attack file is a 1-based index into _mintedLpTokenIds
/// (the LP positions created by mint_lp ops in this run), not a raw on-chain
/// NFT token ID. This makes burn_lp fork-block-independent the actual tokenId
/// is resolved at runtime from the mint_lp that created it.
function _executeBurnLp(string memory line) internal {
uint256 tokenId = vm.parseJsonUint(line, ".tokenId");
uint256 positionIndex = vm.parseJsonUint(line, ".positionIndex");
require(positionIndex >= 1 && positionIndex <= _mintedLpTokenIds.length,
"AttackRunner: burn_lp positionIndex out of range (must be 1-based index of a prior mint_lp op)");
uint256 tokenId = _mintedLpTokenIds[positionIndex - 1];
// Read current liquidity for this token.
(,,,,,,,uint128 liquidity,,,,) = INonfungiblePositionManager(npmAddr).positions(tokenId);
if (liquidity == 0) return;
if (liquidity == 0) {
console.log(string.concat(
"burn_lp: WARNING - tokenId ",
vm.toString(tokenId),
" (positionIndex ",
vm.toString(positionIndex),
") has zero liquidity, skipping (possible fork-block mismatch)"
));
return;
}
vm.startBroadcast(ADV_PK);
INonfungiblePositionManager(npmAddr).decreaseLiquidity(