diff --git a/scripts/bootstrap-common.sh b/scripts/bootstrap-common.sh index ce1ded2..2ee8bf8 100755 --- a/scripts/bootstrap-common.sh +++ b/scripts/bootstrap-common.sh @@ -15,7 +15,7 @@ set -euo pipefail # ── Constants ────────────────────────────────────────────────────────── -FEE_DEST=0x8A9145E1Ea4C4d7FB08cF1011c8ac1F0e10F9383 +FEE_DEST=0xf6a3eef9088A255c32b6aD2025f83E57291D9011 WETH=0x4200000000000000000000000000000000000006 SWAP_ROUTER=0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4 MAX_UINT=0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff @@ -100,52 +100,72 @@ fund_liquidity_manager() { "$LIQUIDITY_MANAGER" --value 10ether >>"$LOG_FILE" 2>&1 } -grant_recenter_access() { - # FEE_DEST is a keccak-derived address with zero balance — fund it for gas - cast rpc --rpc-url "$ANVIL_RPC" anvil_setBalance "$FEE_DEST" "0xDE0B6B3A7640000" >>"$LOG_FILE" 2>&1 || true - bootstrap_log "Granting recenter access to deployer" - cast rpc --rpc-url "$ANVIL_RPC" anvil_impersonateAccount "$FEE_DEST" >>"$LOG_FILE" 2>&1 - cast send --rpc-url "$ANVIL_RPC" --from "$FEE_DEST" --unlocked \ - "$LIQUIDITY_MANAGER" "setRecenterAccess(address)" "$DEPLOYER_ADDR" >>"$LOG_FILE" 2>&1 - cast rpc --rpc-url "$ANVIL_RPC" anvil_stopImpersonatingAccount "$FEE_DEST" >>"$LOG_FILE" 2>&1 - if [[ -n "${TXNBOT_ADDRESS:-}" ]]; then - bootstrap_log "Granting recenter access to txnBot ($TXNBOT_ADDRESS)" - cast rpc --rpc-url "$ANVIL_RPC" anvil_impersonateAccount "$FEE_DEST" >>"$LOG_FILE" 2>&1 - cast send --rpc-url "$ANVIL_RPC" --from "$FEE_DEST" --unlocked \ - "$LIQUIDITY_MANAGER" "setRecenterAccess(address)" "$TXNBOT_ADDRESS" >>"$LOG_FILE" 2>&1 - cast rpc --rpc-url "$ANVIL_RPC" anvil_stopImpersonatingAccount "$FEE_DEST" >>"$LOG_FILE" 2>&1 - fi -} - -call_recenter() { - local recenter_pk="$DEPLOYER_PK" - local recenter_addr="$DEPLOYER_ADDR" - if [[ -n "${TXNBOT_ADDRESS:-}" ]]; then - recenter_pk="$TXNBOT_PRIVATE_KEY" - recenter_addr="$TXNBOT_ADDRESS" - fi - - # If the deploy script already bootstrapped VWAP (cumulativeVolume > 0), positions - # are in place at the post-seed-buy tick. Calling recenter() now would fail with - # "amplitude not reached" because currentTick == anchorCenterTick. Skip it. +bootstrap_vwap() { + # Idempotency guard: if a previous run already bootstrapped VWAP, skip. local cumvol cumvol="$(cast call --rpc-url "$ANVIL_RPC" \ "$LIQUIDITY_MANAGER" "cumulativeVolume()(uint256)" 2>/dev/null || echo "0")" - # cast call with a typed (uint256) selector returns a plain decimal string for - # non-zero values (e.g. "140734553600000") and "0" for zero. A simple != "0" - # check is sufficient; note that the output may include a scientific-notation - # annotation (e.g. "140734553600000 [1.407e14]") which is also != "0", so we - # do NOT attempt to parse it further with cast to-dec (which would fail on the - # annotation and incorrectly fall back to "0"). if [[ "$cumvol" != "0" && -n "$cumvol" ]]; then - bootstrap_log "VWAP already bootstrapped by deploy script (cumulativeVolume=$cumvol) -- skipping initial recenter" + bootstrap_log "VWAP already bootstrapped (cumulativeVolume=$cumvol) -- skipping" return 0 fi - bootstrap_log "Calling recenter() via $recenter_addr" + local recenter_pk="${TXNBOT_PRIVATE_KEY:-$DEPLOYER_PK}" + + # Fund LM with 1 ETH (thin bootstrap positions; 0.5 ETH seed swap moves >400 ticks) + bootstrap_log "Funding LM with 1 ETH for VWAP bootstrap..." + cast send --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \ + "$LIQUIDITY_MANAGER" --value 1ether >>"$LOG_FILE" 2>&1 + + # Advance Anvil time 301s so TWAP oracle has sufficient history for _isPriceStable() + cast rpc --rpc-url "$ANVIL_RPC" evm_increaseTime 301 >>"$LOG_FILE" 2>&1 + cast rpc --rpc-url "$ANVIL_RPC" evm_mine >>"$LOG_FILE" 2>&1 + + # First recenter: places initial bootstrap positions; no fees yet, cumulativeVolume stays 0 + bootstrap_log "First recenter (places bootstrap positions)..." cast send --rpc-url "$ANVIL_RPC" --private-key "$recenter_pk" \ "$LIQUIDITY_MANAGER" "recenter()" >>"$LOG_FILE" 2>&1 + + # Seed buy: wrap 0.5 ETH to WETH and swap WETH->KRK + # Generates a non-zero WETH fee in the anchor position and moves price >400 ticks. + # sqrtPriceLimitX96 is direction-dependent: MIN+1 when WETHKRK)..." + cast send --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \ + "$WETH" "deposit()" --value 0.5ether >>"$LOG_FILE" 2>&1 + cast send --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \ + "$WETH" "approve(address,uint256)" "$SWAP_ROUTER" "$MAX_UINT" >>"$LOG_FILE" 2>&1 + + local weth_addr kraiken_addr sqrt_limit + weth_addr=$(echo "$WETH" | tr '[:upper:]' '[:lower:]' | sed 's/^0x//') + kraiken_addr=$(echo "$KRAIKEN" | tr '[:upper:]' '[:lower:]' | sed 's/^0x//') + if [[ "$weth_addr" < "$kraiken_addr" ]]; then + sqrt_limit=4295128740 # WETH=token0, zeroForOne=true, price decreases + else + sqrt_limit=1461446703485210103287273052203988822378723970341 # WETH=token1, price increases + fi + + cast send --legacy --gas-limit 300000 --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \ + "$SWAP_ROUTER" "exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))" \ + "($WETH,$KRAIKEN,10000,$DEPLOYER_ADDR,500000000000000000,0,$sqrt_limit)" >>"$LOG_FILE" 2>&1 + + # Advance time 301s so TWAP settles at post-buy price and cooldown (60s) elapses + cast rpc --rpc-url "$ANVIL_RPC" evm_increaseTime 301 >>"$LOG_FILE" 2>&1 + cast rpc --rpc-url "$ANVIL_RPC" evm_mine >>"$LOG_FILE" 2>&1 + + # Second recenter: cumulativeVolume==0 path fires (bootstrap), ethFee>0 -> records VWAP + bootstrap_log "Second recenter (records VWAP)..." + cast send --rpc-url "$ANVIL_RPC" --private-key "$recenter_pk" \ + "$LIQUIDITY_MANAGER" "recenter()" >>"$LOG_FILE" 2>&1 + + # Verify VWAP bootstrap succeeded + cumvol="$(cast call --rpc-url "$ANVIL_RPC" \ + "$LIQUIDITY_MANAGER" "cumulativeVolume()(uint256)" 2>/dev/null || echo "0")" + if [[ "$cumvol" == "0" || -z "$cumvol" ]]; then + bootstrap_log "ERROR: VWAP bootstrap failed -- cumulativeVolume is 0" + return 1 + fi + bootstrap_log "VWAP bootstrapped (cumulativeVolume=$cumvol)" } seed_application_state() { @@ -176,8 +196,8 @@ seed_application_state() { fi bootstrap_log "Swap returned 0 KRK — recentering and retrying" - # Mine a few blocks to advance time, then recenter - cast rpc --rpc-url "$ANVIL_RPC" evm_mine >>"$LOG_FILE" 2>&1 || true + # Advance 61 s to clear the 60-second recenter cooldown, then mine a block. + cast rpc --rpc-url "$ANVIL_RPC" evm_increaseTime 61 >>"$LOG_FILE" 2>&1 || true cast rpc --rpc-url "$ANVIL_RPC" evm_mine >>"$LOG_FILE" 2>&1 || true local recenter_pk="${TXNBOT_PRIVATE_KEY:-$DEPLOYER_PK}" cast send --rpc-url "$ANVIL_RPC" --private-key "$recenter_pk" \