fix: address review feedback on mainnet-bootstrap runbook (#728)
- docs/mainnet-bootstrap.md: fix Step 4c to use SwapRouter02 7-field struct (no deadline field); the 8-field ABI was for SwapRouter v1 but the address is SwapRouter02 - docs/mainnet-bootstrap.md: correct Step 1 to no longer falsely claim that pre-bootstrap transactions succeed when Forge aborts on simulation failure; Step 1 now reflects the try/catch behaviour added below - docs/mainnet-bootstrap.md: Step 6 drops --private-key flag (Foundry ignores it when vm.startBroadcast(privateKey) is called internally) and documents that the .secret seed-phrase file must be present - docs/mainnet-bootstrap.md: remove no-op `export LM_ADDRESS="$LM_ADDRESS"` - docs/mainnet-bootstrap.md: cite exact line range (101-145) in Troubleshooting workaround instead of informal marker description - onchain/script/DeployBase.sol: wrap liquidityManager.recenter() and seed buy in try/catch so a fresh-pool TWAP revert skips the inline bootstrap with a warning rather than aborting the entire simulation - onchain/script/DeployBase.sol: fix --fork-url to --rpc-url in the post-deploy console.log hint Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
973caff062
commit
4d16a51650
2 changed files with 28 additions and 21 deletions
|
|
@ -39,7 +39,7 @@ export DEPLOYER_ADDRESS="$(cast wallet address --private-key $DEPLOYER_KEY)"
|
|||
|
||||
## Step 1 — Deploy contracts (pool init)
|
||||
|
||||
Run the mainnet deploy script. The inline bootstrap section in `DeployBase.sol` will revert on a fresh pool — that is expected. All contract deployments that precede the bootstrap attempt will succeed and be confirmed on-chain.
|
||||
Run the mainnet deploy script. `DeployBase.sol` wraps the inline `recenter()` call in a try/catch, so if the pool is too fresh for the TWAP oracle the bootstrap is skipped with a warning and the deployment still succeeds. The deploy script then prints instructions directing you to complete the bootstrap manually.
|
||||
|
||||
```bash
|
||||
cd onchain
|
||||
|
|
@ -53,7 +53,7 @@ forge script script/DeployBaseMainnet.sol \
|
|||
--private-key $DEPLOYER_KEY
|
||||
```
|
||||
|
||||
> **Note:** If Forge aborts the simulation before broadcast due to the `recenter()` revert, see [Troubleshooting](#troubleshooting) below for how to separate the deploy from the bootstrap.
|
||||
> **Note:** If the script still aborts during simulation (e.g., due to an older version of `DeployBase.sol` without the try/catch), see [Troubleshooting](#troubleshooting) for how to separate the deploy from the bootstrap.
|
||||
|
||||
After the broadcast completes, record the addresses from the console output:
|
||||
|
||||
|
|
@ -155,12 +155,11 @@ cast send $WETH \
|
|||
--private-key $DEPLOYER_KEY
|
||||
|
||||
# Step 4c — Seed buy: swap 0.005 WETH → KRAIKEN via the 1 % pool
|
||||
# Struct fields: tokenIn, tokenOut, fee, recipient, deadline, amountIn, amountOutMinimum, sqrtPriceLimitX96
|
||||
DEADLINE=$(( $(cast block latest --rpc-url $BASE_RPC --field timestamp) + 1800 ))
|
||||
|
||||
# SwapRouter02 exactInputSingle struct (7 fields — no deadline):
|
||||
# tokenIn, tokenOut, fee, recipient, amountIn, amountOutMinimum, sqrtPriceLimitX96
|
||||
cast send $SWAP_ROUTER \
|
||||
"exactInputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))(uint256)" \
|
||||
"($WETH,$KRAIKEN,10000,$DEPLOYER_ADDRESS,$DEADLINE,5000000000000000,0,0)" \
|
||||
"exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))(uint256)" \
|
||||
"($WETH,$KRAIKEN,10000,$DEPLOYER_ADDRESS,5000000000000000,0,0)" \
|
||||
--rpc-url $BASE_RPC \
|
||||
--private-key $DEPLOYER_KEY
|
||||
|
||||
|
|
@ -199,13 +198,14 @@ done
|
|||
The second `recenter()` hits the bootstrap path inside `LiquidityManager`: `cumulativeVolume == 0` and `ethFee > 0`, so it records the VWAP price anchor and sets `cumulativeVolume > 0`, permanently closing the bootstrap window.
|
||||
|
||||
```bash
|
||||
export LM_ADDRESS="$LM_ADDRESS" # must be set
|
||||
|
||||
# LM_ADDRESS must already be set from Step 1.
|
||||
# BootstrapVWAPPhase2.s.sol reads the broadcaster key from the .secret
|
||||
# seed-phrase file in onchain/ (same as DeployBase.sol). Ensure that file
|
||||
# is present; the --private-key CLI flag is NOT used by this script.
|
||||
forge script script/BootstrapVWAPPhase2.s.sol \
|
||||
--tc BootstrapVWAPPhase2 \
|
||||
--rpc-url $BASE_RPC \
|
||||
--broadcast \
|
||||
--private-key $DEPLOYER_KEY
|
||||
--broadcast
|
||||
```
|
||||
|
||||
The script asserts `cumulativeVolume > 0` and will fail with an explicit message if the bootstrap did not succeed.
|
||||
|
|
@ -240,7 +240,7 @@ cast balance $LM_ADDRESS --rpc-url $BASE_RPC
|
|||
|
||||
Foundry simulates the entire `run()` function before broadcasting anything. If the inline bootstrap in `DeployBase.sol` causes the simulation to fail, no transactions are broadcast.
|
||||
|
||||
**Workaround:** Comment out the bootstrap block (lines marked `VWAP Bootstrap`) in `DeployBase.sol` locally before running the deploy script, then restore it afterward. The bootstrap is then performed manually using Steps 3–6 above.
|
||||
**Workaround:** Comment out the bootstrap block in `DeployBase.sol` locally (lines 101–145, from `// =====================================================================` through `seedSwapper.executeSeedBuy{ value: SEED_SWAP_ETH }(sender);`) before running the deploy script, then restore it afterward. The bootstrap is then performed manually using Steps 3–6 above.
|
||||
|
||||
### `recenter()` reverts with "price deviated from oracle"
|
||||
|
||||
|
|
|
|||
|
|
@ -128,17 +128,24 @@ contract DeployBase is Script {
|
|||
console.log("feeDestination set to", feeDest);
|
||||
|
||||
// Step 2: Fund LM and place initial bootstrap positions.
|
||||
// NOTE: recenter() requires TWAP history (>= 300s since pool init).
|
||||
// On Base mainnet this call will revert if the pool is too fresh.
|
||||
// recenter() requires TWAP history (>= 300s since pool init).
|
||||
// On a fresh mainnet pool this will revert; the try/catch allows the
|
||||
// deploy to succeed and the operator completes the bootstrap manually
|
||||
// by following docs/mainnet-bootstrap.md.
|
||||
(bool funded,) = address(liquidityManager).call{ value: SEED_LM_ETH }("");
|
||||
require(funded, "Failed to fund LM for seed bootstrap");
|
||||
liquidityManager.recenter();
|
||||
try liquidityManager.recenter() {
|
||||
console.log("First recenter complete -> positions placed, cumulativeVolume still 0");
|
||||
|
||||
// Step 3: Seed buy -> generates a non-zero fee in the anchor position.
|
||||
SeedSwapper seedSwapper = new SeedSwapper(weth, address(pool), token0isWeth);
|
||||
seedSwapper.executeSeedBuy{ value: SEED_SWAP_ETH }(sender);
|
||||
console.log("Seed buy executed -> fee generated in anchor position");
|
||||
} catch {
|
||||
console.log("WARNING: recenter() reverted - inline bootstrap skipped.");
|
||||
console.log(" Pool likely has < 300 s of TWAP history.");
|
||||
console.log(" Follow docs/mainnet-bootstrap.md (Phase 2 steps) to complete.");
|
||||
}
|
||||
|
||||
// Step 4: Second recenter records VWAP (bootstrap path + ethFee > 0).
|
||||
// Cannot be called in the same Forge broadcast as Step 2 — recenter() enforces a
|
||||
|
|
@ -153,7 +160,7 @@ contract DeployBase is Script {
|
|||
console.log("Optimizer:", optimizerAddress);
|
||||
console.log("\nPost-deploy steps:");
|
||||
console.log(" 1. Wait >= 60 s after this script finishes.");
|
||||
console.log(" 2. Run: forge script script/BootstrapVWAPPhase2.s.sol --tc BootstrapVWAPPhase2 --fork-url <RPC> --broadcast");
|
||||
console.log(" 2. Run: forge script script/BootstrapVWAPPhase2.s.sol --tc BootstrapVWAPPhase2 --rpc-url <RPC> --broadcast");
|
||||
console.log(" This performs the second recenter that records cumulativeVolume > 0.");
|
||||
console.log(" 3. Fund LiquidityManager with operational ETH.");
|
||||
console.log(" 4. recenter() is permissionless - any address (e.g. txnBot) can call it.");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue