PROBLEM: Recenter operations were burning ~137,866 KRK tokens instead of minting them, causing severe deflation when inflation should occur. This was due to the liquidity manager burning ALL collected tokens from old positions and then minting tokens for new positions separately, causing asymmetric supply adjustments to the staking pool. ROOT CAUSE: During recenter(): 1. _scrapePositions() collected tokens from old positions and immediately burned them ALL (+ proportional staking pool adjustment) 2. _setPositions() minted tokens for new positions (+ proportional staking pool adjustment) 3. The burn and mint operations used DIFFERENT totalSupply values in their proportion calculations, causing imbalanced adjustments 4. When old positions had more tokens than new positions needed, the net result was deflation WHY THIS HAPPENED: When KRK price increases (users buying), the same liquidity depth requires fewer KRK tokens. The old code would: - Burn 120k KRK from old positions (+ 30k from staking pool) - Mint 10k KRK for new positions (+ 2.5k to staking pool) - Net: -137.5k KRK total supply (WRONG!) FIX: 1. Modified uniswapV3MintCallback() to use existing KRK balance first before minting new tokens 2. Removed burn() from _scrapePositions() - keep collected tokens 3. Removed burn() from end of recenter() - don't burn "excess" 4. Tokens held by LiquidityManager are already excluded from outstandingSupply(), so they don't affect staking calculations RESULT: Now during recenter, only the NET difference is minted or used: - Collect old positions into LiquidityManager balance - Use that balance for new positions - Only mint additional tokens if more are needed - Keep any unused balance for future recenters - No more asymmetric burn/mint causing supply corruption VERIFICATION: - All 107 existing tests pass - Added 2 new regression tests in test/SupplyCorruption.t.sol - testRecenterDoesNotCorruptSupply: verifies single recenter preserves supply - testMultipleRecentersPreserveSupply: verifies no accumulation over time Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| .github/workflows | ||
| .husky | ||
| analysis | ||
| lib | ||
| script | ||
| src | ||
| test | ||
| .gitignore | ||
| .lintstagedrc.json | ||
| .secret.local | ||
| .solhint.json | ||
| .solhintignore | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| deployments-local.json | ||
| foundry.toml | ||
| hAIrberger.md | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| remappings.txt | ||
| testing_todos.md | ||
| UNISWAP_V3_MATH.md | ||
Foundry
Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.
Foundry consists of:
- Forge: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- Cast: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- Anvil: Local Ethereum node, akin to Ganache, Hardhat Network.
- Chisel: Fast, utilitarian, and verbose solidity REPL.
Documentation
Usage
Install
$ git clone
$ git submodule init
$ git submodule update
$ cd lib/uni-v3-lib
$ yarn
Build
$ forge build
Test
$ forge test
Format
$ forge fmt
Gas Snapshots
$ forge snapshot
Anvil
$ anvil
Deploy
forge clean
forge cache clean
source .env
forge script script/BaseSepoliaDeploy.sol:BaseSepoliaDeploy --slow --broadcast --verify --rpc-url ${BASE_SEPOLIA_RPC_URL}
if verification fails:
forge verify-contract --watch --chain sepolia --constructor-args $(cast abi-encode "constructor(string,string,address,address,address)" "Kraiken" "KRAIKEN" "0x0227628f3F023bb0B980b67D528571c95c6DaC1c" "0xb16F35c0Ae2912430DAc15764477E179D9B9EbEa" "0x64dda11815b883c589afed914666ef2d63c8c338") 0x7517db0f2b24223f2f0e3567149ca180e204da8a Kraiken
forge verify-contract --watch --chain sepolia --constructor-args $(cast abi-encode "constructor(address)" "0x7517db0f2b24223f2f0e3567149ca180e204da8a") 0x00b4d656b8182d0c2f4841b7a6f1429b94f73a66 Stake
Cast
$ cast <subcommand>
Help
$ forge --help
$ anvil --help
$ cast --help
Deployment on Base Sepolia
Multisig
address: 0xf6a3eef9088A255c32b6aD2025f83E57291D9011
Kraiken
address: 0x22c264Ecf8D4E49D1E3CabD8DD39b7C4Ab51C1B8
Stake
address: 0xe28020BCdEeAf2779dd47c670A8eFC2973316EE2
LP
address: 0x3d6a8797693a0bC598210782B6a889E11A2340Cd
Deployment on Base
Kraiken
address: 0x45caa5929f6ee038039984205bdecf968b954820
Stake
address: 0xed70707fab05d973ad41eae8d17e2bcd36192cfc
LP
address: 0x7fd4e645ce258dd3942eddbeb2f99137da8ba13b
References
open features:
- reduce snatch collision
todos:
- write unit test for capital exit function
- would anchorLiquidityShare affect capitalInefficiency?
- could the UBI pool run dry?
- what happens if discovery runs out?
Simulation data:
{ "VWAP":0,
"comEthBal":1234,
"comHarbBal":0,
"comStakeShare":0,
"liquidity":[{
"liquidity":1234,
"tickLower":-123,
"tickUpper":124
}],
"startTime":1234,
"txns":[{
"action":5,"timeOffset":0,"x":0,"y":""},
{"action":0,"ethAmount":1,"x":0,"y":""},
{"action":5,"timeOffset":0,"x":0,"y":""},
{"action":0,"ethAmount":2,"x":0,"y":""},
{"action":5,"timeOffset":0,"x":0,"y":""},
{"action":0,"ethAmount":4,"x":0,"y":""},
{"action":2,"harbAmount":3000,"tax":10,"y":""},
{"action":5,"timeOffset":0,"x":0,"y":""},
{"action":4,"positionId":654321,"x":0,"y":""},
{"action":2,"harbAmount":5000,"tax":20,"y":""},
{"action":0,"ethAmount":8,"x":0,"y":""},
{"action":5,"timeOffset":0,"x":0,"y":""},
{"action":1,"harbAmount":20000,"x":0,"y":""},
{"action":5,"timeOffset":0,"x":0,"y":""},
{"action":4,"positionId":654321,"x":0,"y":""},
{"action":2,"harbAmount":8000,"tax":29,"y":""}
]
}