2026-02-03 12:07:28 +01:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
# Shared bootstrap functions for local dev and CI.
|
|
|
|
|
# Source this file after setting these variables:
|
|
|
|
|
# ANVIL_RPC - Anvil JSON-RPC URL (required)
|
|
|
|
|
# DEPLOYER_PK - Deployer private key (defaults to Anvil account 0)
|
|
|
|
|
# DEPLOYER_ADDR - Deployer address (defaults to Anvil account 0)
|
|
|
|
|
# TXNBOT_ADDRESS - TxnBot wallet address (optional)
|
|
|
|
|
# TXNBOT_PRIVATE_KEY- TxnBot private key (optional)
|
|
|
|
|
# TXNBOT_FUND_VALUE - Amount to fund txnBot (default: 1ether)
|
|
|
|
|
# CONTRACT_ENV - Path to write contracts.env (required)
|
|
|
|
|
# LOG_FILE - Log file for cast/forge output (default: /dev/null)
|
|
|
|
|
# ONCHAIN_DIR - Path to onchain/ directory (required)
|
|
|
|
|
# KRAIKEN_LIB_DIR - Path to kraiken-lib/ directory (optional, for CI build)
|
|
|
|
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
# ── Constants ──────────────────────────────────────────────────────────
|
|
|
|
|
FEE_DEST=0xf6a3eef9088A255c32b6aD2025f83E57291D9011
|
|
|
|
|
WETH=0x4200000000000000000000000000000000000006
|
|
|
|
|
SWAP_ROUTER=0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4
|
|
|
|
|
MAX_UINT=0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
|
|
|
|
|
|
|
|
DEFAULT_DEPLOYER_PK=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
|
|
|
|
|
DEFAULT_DEPLOYER_ADDR=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
|
|
|
|
|
|
|
|
|
|
DEFAULT_TXNBOT_PK=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
|
|
|
|
|
DEFAULT_TXNBOT_ADDR=0x70997970C51812dc3A010C7d01b50e0d17dc79C8
|
|
|
|
|
|
|
|
|
|
# ── Defaults ───────────────────────────────────────────────────────────
|
|
|
|
|
DEPLOYER_PK=${DEPLOYER_PK:-$DEFAULT_DEPLOYER_PK}
|
|
|
|
|
DEPLOYER_ADDR=${DEPLOYER_ADDR:-$DEFAULT_DEPLOYER_ADDR}
|
|
|
|
|
TXNBOT_FUND_VALUE=${TXNBOT_FUND_VALUE:-1ether}
|
|
|
|
|
LOG_FILE=${LOG_FILE:-/dev/null}
|
|
|
|
|
|
|
|
|
|
# ── Helpers ────────────────────────────────────────────────────────────
|
|
|
|
|
bootstrap_log() {
|
|
|
|
|
echo "[bootstrap] $*"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ── Functions ──────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
wait_for_rpc() {
|
|
|
|
|
for _ in {1..120}; do
|
|
|
|
|
if cast chain-id --rpc-url "$ANVIL_RPC" >/dev/null 2>&1; then
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
sleep 1
|
|
|
|
|
done
|
|
|
|
|
bootstrap_log "Timed out waiting for Anvil at $ANVIL_RPC"
|
|
|
|
|
return 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
run_forge_script() {
|
|
|
|
|
bootstrap_log "Deploying contracts to fork"
|
|
|
|
|
pushd "$ONCHAIN_DIR" >/dev/null
|
2026-03-12 23:12:25 +00:00
|
|
|
forge script script/DeployLocal.sol --tc DeployLocal --fork-url "$ANVIL_RPC" --broadcast >>"$LOG_FILE" 2>&1
|
2026-02-03 12:07:28 +01:00
|
|
|
popd >/dev/null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extract_addresses() {
|
|
|
|
|
local run_file
|
|
|
|
|
run_file="$(ls -t "$ONCHAIN_DIR/broadcast/DeployLocal.sol"/*/run-latest.json 2>/dev/null | head -n1)"
|
|
|
|
|
if [[ -z "$run_file" ]]; then
|
|
|
|
|
bootstrap_log "Deployment artifact not found"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
bootstrap_log "Using artifact $run_file"
|
|
|
|
|
LIQUIDITY_MANAGER="$(jq -r '.transactions[] | select(.contractName=="LiquidityManager") | .contractAddress' "$run_file" | head -n1)"
|
|
|
|
|
KRAIKEN="$(jq -r '.transactions[] | select(.contractName=="Kraiken") | .contractAddress' "$run_file" | head -n1)"
|
|
|
|
|
STAKE="$(jq -r '.transactions[] | select(.contractName=="Stake") | .contractAddress' "$run_file" | head -n1)"
|
feat: OptimizerV3 with direct 2D staking-to-LP parameter mapping
Core protocol changes for launch readiness:
- OptimizerV3: binary bear/bull mapping from (staking%, avgTax) — avoids
exploitable AW 30-90 kill zone. Bear: AS=30%, AW=100, CI=0, DD=0.3e18.
Bull: AS=100%, AW=20, CI=0, DD=1e18. UUPS upgradeable with __gap[48].
- Directional VWAP: only records prices on ETH inflow (buys), preventing
sell-side dilution of price memory
- Floor formula: unified max(scarcity, mirror, clamp) — VWAP mirror uses
distance from adjusted VWAP as floor distance, no branching
- PriceOracle (M-1 fix): correct fallback TWAP divisor (60000s, not 300s)
- Access control (M-2 fix): deployer-only guard on one-time setters
- Recenter rate limit (M-3 fix): 60-second cooldown for open recenters
- Safe fallback params: recenter() optimizer-failure defaults changed from
exploitable CI=50%/AW=50 to safe bear-mode CI=0/AW=100
- Recentered event for monitoring and indexing
- VERSION bump to 2, kraiken-lib COMPATIBLE_CONTRACT_VERSIONS updated
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:21:18 +00:00
|
|
|
OPTIMIZER_PROXY="$(jq -r '.transactions[] | select(.contractName=="ERC1967Proxy") | .contractAddress' "$run_file" | head -n1)"
|
2026-02-03 12:07:28 +01:00
|
|
|
DEPLOY_BLOCK="$(jq -r '.receipts[0].blockNumber' "$run_file" | xargs printf "%d")"
|
|
|
|
|
if [[ -z "$LIQUIDITY_MANAGER" || "$LIQUIDITY_MANAGER" == "null" ]]; then
|
|
|
|
|
bootstrap_log "LiquidityManager address missing"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write_contracts_env() {
|
|
|
|
|
cat >"$CONTRACT_ENV" <<EOCONTRACTS
|
|
|
|
|
LIQUIDITY_MANAGER=$LIQUIDITY_MANAGER
|
|
|
|
|
KRAIKEN=$KRAIKEN
|
|
|
|
|
STAKE=$STAKE
|
|
|
|
|
EOCONTRACTS
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fund_liquidity_manager() {
|
|
|
|
|
bootstrap_log "Funding LiquidityManager"
|
|
|
|
|
cast send --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \
|
2026-02-18 00:19:05 +01:00
|
|
|
"$LIQUIDITY_MANAGER" --value 10ether >>"$LOG_FILE" 2>&1
|
2026-02-03 12:07:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
grant_recenter_access() {
|
|
|
|
|
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
|
2026-03-12 21:46:00 +00:00
|
|
|
|
|
|
|
|
# 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.
|
|
|
|
|
local cumvol
|
|
|
|
|
cumvol="$(cast call --rpc-url "$ANVIL_RPC" \
|
|
|
|
|
"$LIQUIDITY_MANAGER" "cumulativeVolume()(uint256)" 2>/dev/null || echo "0")"
|
|
|
|
|
if [[ "$cumvol" != "0" && -n "$cumvol" ]]; then
|
|
|
|
|
bootstrap_log "VWAP already bootstrapped by deploy script (cumulativeVolume=$cumvol) -- skipping initial recenter"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
2026-02-03 12:07:28 +01:00
|
|
|
bootstrap_log "Calling recenter() via $recenter_addr"
|
|
|
|
|
cast send --rpc-url "$ANVIL_RPC" --private-key "$recenter_pk" \
|
|
|
|
|
"$LIQUIDITY_MANAGER" "recenter()" >>"$LOG_FILE" 2>&1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
seed_application_state() {
|
|
|
|
|
bootstrap_log "Wrapping ETH to WETH"
|
|
|
|
|
cast send --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \
|
2026-02-18 00:19:05 +01:00
|
|
|
"$WETH" "deposit()" --value 2ether >>"$LOG_FILE" 2>&1
|
2026-02-03 12:07:28 +01:00
|
|
|
bootstrap_log "Approving router"
|
|
|
|
|
cast send --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \
|
|
|
|
|
"$WETH" "approve(address,uint256)" "$SWAP_ROUTER" "$MAX_UINT" >>"$LOG_FILE" 2>&1
|
2026-02-20 09:19:13 +01:00
|
|
|
|
|
|
|
|
# Swap with retry — recenter may not position liquidity at the right tick on first call
|
|
|
|
|
local swap_success=false
|
|
|
|
|
for attempt in 1 2 3; do
|
|
|
|
|
bootstrap_log "KRK swap attempt $attempt/3"
|
|
|
|
|
local balance_before balance_after
|
|
|
|
|
balance_before=$(cast call --rpc-url "$ANVIL_RPC" "$KRAIKEN" "balanceOf(address)(uint256)" "$DEPLOYER_ADDR" 2>/dev/null || echo "0")
|
|
|
|
|
|
|
|
|
|
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,1000000000000000000,0,4295128740)" >>"$LOG_FILE" 2>&1 || true
|
|
|
|
|
|
|
|
|
|
balance_after=$(cast call --rpc-url "$ANVIL_RPC" "$KRAIKEN" "balanceOf(address)(uint256)" "$DEPLOYER_ADDR" 2>/dev/null || echo "0")
|
|
|
|
|
|
|
|
|
|
if [[ "$balance_after" != "$balance_before" && "$balance_after" != "0" ]]; then
|
|
|
|
|
bootstrap_log "Swap successful — got KRK tokens (balance: $balance_after)"
|
|
|
|
|
swap_success=true
|
|
|
|
|
break
|
|
|
|
|
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
|
|
|
|
|
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" \
|
|
|
|
|
"$LIQUIDITY_MANAGER" "recenter()" >>"$LOG_FILE" 2>&1 || true
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
if [[ "$swap_success" != "true" ]]; then
|
|
|
|
|
bootstrap_log "WARNING: All swap attempts returned 0 KRK. Pool may have no liquidity at current tick."
|
|
|
|
|
fi
|
2026-02-03 12:07:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fund_txn_bot_wallet() {
|
|
|
|
|
if [[ -z "${TXNBOT_ADDRESS:-}" ]]; then
|
|
|
|
|
return
|
|
|
|
|
fi
|
|
|
|
|
bootstrap_log "Funding txnBot wallet $TXNBOT_ADDRESS with $TXNBOT_FUND_VALUE"
|
|
|
|
|
cast send --rpc-url "$ANVIL_RPC" --private-key "$DEPLOYER_PK" \
|
|
|
|
|
"$TXNBOT_ADDRESS" --value "$TXNBOT_FUND_VALUE" >>"$LOG_FILE" 2>&1 || true
|
|
|
|
|
local wei hex
|
|
|
|
|
wei="$(cast --to-unit "$TXNBOT_FUND_VALUE" wei)"
|
|
|
|
|
hex="$(cast --to-hex "$wei")"
|
|
|
|
|
cast rpc --rpc-url "$ANVIL_RPC" anvil_setBalance "$TXNBOT_ADDRESS" "$hex" >>"$LOG_FILE" 2>&1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write_deployments_json() {
|
|
|
|
|
local target="${1:-$ONCHAIN_DIR/deployments-local.json}"
|
|
|
|
|
cat >"$target" <<EODEPLOYMENTS
|
|
|
|
|
{
|
|
|
|
|
"contracts": {
|
|
|
|
|
"Kraiken": "$KRAIKEN",
|
|
|
|
|
"Stake": "$STAKE",
|
feat: OptimizerV3 with direct 2D staking-to-LP parameter mapping
Core protocol changes for launch readiness:
- OptimizerV3: binary bear/bull mapping from (staking%, avgTax) — avoids
exploitable AW 30-90 kill zone. Bear: AS=30%, AW=100, CI=0, DD=0.3e18.
Bull: AS=100%, AW=20, CI=0, DD=1e18. UUPS upgradeable with __gap[48].
- Directional VWAP: only records prices on ETH inflow (buys), preventing
sell-side dilution of price memory
- Floor formula: unified max(scarcity, mirror, clamp) — VWAP mirror uses
distance from adjusted VWAP as floor distance, no branching
- PriceOracle (M-1 fix): correct fallback TWAP divisor (60000s, not 300s)
- Access control (M-2 fix): deployer-only guard on one-time setters
- Recenter rate limit (M-3 fix): 60-second cooldown for open recenters
- Safe fallback params: recenter() optimizer-failure defaults changed from
exploitable CI=50%/AW=50 to safe bear-mode CI=0/AW=100
- Recentered event for monitoring and indexing
- VERSION bump to 2, kraiken-lib COMPATIBLE_CONTRACT_VERSIONS updated
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:21:18 +00:00
|
|
|
"LiquidityManager": "$LIQUIDITY_MANAGER",
|
|
|
|
|
"OptimizerProxy": "$OPTIMIZER_PROXY"
|
2026-02-03 12:07:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EODEPLOYMENTS
|
|
|
|
|
}
|