diff --git a/docs/mainnet-bootstrap.md b/docs/mainnet-bootstrap.md index 63abafd..b8fc6f2 100644 --- a/docs/mainnet-bootstrap.md +++ b/docs/mainnet-bootstrap.md @@ -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" diff --git a/onchain/script/DeployBase.sol b/onchain/script/DeployBase.sol index 15c58fd..8f66cdf 100644 --- a/onchain/script/DeployBase.sol +++ b/onchain/script/DeployBase.sol @@ -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(); - console.log("First recenter complete -> positions placed, cumulativeVolume still 0"); + 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"); + // 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 --broadcast"); + console.log(" 2. Run: forge script script/BootstrapVWAPPhase2.s.sol --tc BootstrapVWAPPhase2 --rpc-url --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.");