From efb7e7309804861f87471bef5a2f6da519461092 Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:26:04 +0000 Subject: [PATCH 01/16] chore: update devnet to xion v28.1.0 - Update XIOND_VERSION from 20.0.0 to 28.1.0 - Update xion submodule branch from release/v20 to release/v28 - Add 'zk' module to IMPORT_MODULES array in entrypoint.sh - SOURCE_CHAIN_CODE_IDS unchanged (1=account, 1260=treasury on testnet-2) Ref: DO-239 --- .env | 2 +- .gitmodules | 2 +- scripts/init/entrypoint.sh | 1 + xion | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.env b/.env index 59d8209..089977c 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -XIOND_VERSION="20.0.0" +XIOND_VERSION="28.1.0" CHAIN_ID="xion-devnet-1" DAEMON_HOME="/home/xiond/.xiond" diff --git a/.gitmodules b/.gitmodules index cd4821b..a75b216 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "xion"] path = xion url = https://github.com/burnt-labs/xion.git - branch = release/v20 + branch = release/v28 [submodule "xion-dashboard-app"] path = xion-dashboard-app url = https://github.com/burnt-labs/xion-dashboard-app.git diff --git a/scripts/init/entrypoint.sh b/scripts/init/entrypoint.sh index b1c92c7..437fa35 100755 --- a/scripts/init/entrypoint.sh +++ b/scripts/init/entrypoint.sh @@ -21,6 +21,7 @@ IMPORT_MODULES=( "staking" "tokenfactory" "wasm" + "zk" ) # Load environment variables diff --git a/xion b/xion index aaa3800..0d22d35 160000 --- a/xion +++ b/xion @@ -1 +1 @@ -Subproject commit aaa380084f0453af96577f34095f456c80c6988f +Subproject commit 0d22d35af0b4d4bf2162ec5fb8506eb0aae9054b From 09df34b548deae751b95a71332897444d40a63ea Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:26:04 +0000 Subject: [PATCH 02/16] chore: add dkim module to IMPORT_MODULES New x/dkim module in xion v28 needs params imported from source chain. Ref: DO-239 --- scripts/init/entrypoint.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/init/entrypoint.sh b/scripts/init/entrypoint.sh index 437fa35..2b04ba5 100755 --- a/scripts/init/entrypoint.sh +++ b/scripts/init/entrypoint.sh @@ -12,6 +12,7 @@ IMPORT_MODULES=( "bank" "bank_denoms_metadata" "consensus" + "dkim" "distribution" "globalfee" "gov" From 87df758fc849935ff4a65df46a5e4ff9946a8fca Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:26:04 +0000 Subject: [PATCH 03/16] feat(devnet): add core app services (AA API, Dashboard, Indexer, Staking) Phase 2 (DO-240): - Add account-abstraction-api and xion-indexer as new submodules - Update xion-dashboard-app and xion-staking submodule pointers - Add docker-compose services: AA API, Indexer (Postgres + SubQuery node + GraphQL), Dashboard, Staking - Add HAProxy backends for all new services (ports 3001-3004) - Add indexer-db volume for Postgres persistence Submodule changes: - xion-indexer: added xion-devnet-1 network config in project.ts - xion-staking: switched to standalone output for Docker compatibility --- .gitmodules | 8 +++ account-abstraction-api | 1 + config/haproxy.cfg | 20 ++++++ docker-compose.yml | 131 ++++++++++++++++++++++++++++++++++++++++ xion-dashboard-app | 2 +- xion-indexer | 1 + xion-staking | 2 +- 7 files changed, 163 insertions(+), 2 deletions(-) create mode 160000 account-abstraction-api create mode 160000 xion-indexer diff --git a/.gitmodules b/.gitmodules index a75b216..117b302 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,3 +26,11 @@ path = xion-assets url = https://github.com/burnt-labs/xion-assets.git branch = chore/devnet +[submodule "xion-indexer"] + path = xion-indexer + url = https://github.com/burnt-labs/xion-indexer.git + branch = chore/devnet +[submodule "account-abstraction-api"] + path = account-abstraction-api + url = https://github.com/burnt-labs/account-abstraction-api.git + branch = chore/devnet diff --git a/account-abstraction-api b/account-abstraction-api new file mode 160000 index 0000000..df1694e --- /dev/null +++ b/account-abstraction-api @@ -0,0 +1 @@ +Subproject commit df1694e63d598478ce2c4080f3257fff46c696c7 diff --git a/config/haproxy.cfg b/config/haproxy.cfg index 6747182..4b93cd6 100644 --- a/config/haproxy.cfg +++ b/config/haproxy.cfg @@ -51,3 +51,23 @@ listen explorer bind *:5173 mode http server xion-explorer xion-explorer:5173 check resolvers default + +listen aa-api + bind *:3001 + mode http + server account-abstraction-api account-abstraction-api:3000 check resolvers default + +listen indexer + bind *:3002 + mode http + server xion-indexer-graphql xion-indexer-graphql:3000 check resolvers default + +listen dashboard + bind *:3003 + mode http + server xion-dashboard-app xion-dashboard-app:3000 check resolvers default + +listen staking + bind *:3004 + mode http + server xion-staking xion-staking:3000 check resolvers default diff --git a/docker-compose.yml b/docker-compose.yml index 772ce8f..cafddc1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,10 @@ services: ports: - 1317:1317 - 3000:3000 + - 3001:3001 + - 3002:3002 + - 3003:3003 + - 3004:3004 - 5173:5173 - 9090:9090 - 26657:26657 @@ -83,8 +87,135 @@ services: networks: - default + # === Core Apps (Phase 2) === + + account-abstraction-api: + build: + context: account-abstraction-api/ + image: ghcr.io/burnt-labs/xion/account-abstraction-api:latest + environment: + - XION_RPC_URL=http://haproxy:26657 + - XION_API_URL=http://haproxy:1317 + - XION_GRPC_URL=haproxy:9090 + - CHAIN_ID=xion-devnet-1 + ports: + - "3000" + depends_on: + xion: + condition: service_healthy + networks: + - default + + xion-indexer-db: + image: postgres:16-alpine + environment: + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - "5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + volumes: + - indexer-db:/var/lib/postgresql/data + networks: + - default + + xion-indexer-node: + image: subquerynetwork/subql-node-cosmos:v3.11.2 + depends_on: + xion-indexer-db: + condition: service_healthy + xion: + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: xion-indexer-db + DB_PORT: 5432 + volumes: + - ./xion-indexer:/app + command: + - ${SUB_COMMAND:-forceClean} + - -f=/app + - --db-schema=app + - --unsafe + healthcheck: + test: ["CMD", "curl", "-f", "http://xion-indexer-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + networks: + - default + + xion-indexer-graphql: + image: subquerynetwork/subql-query:latest + depends_on: + xion-indexer-db: + condition: service_healthy + xion-indexer-node: + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: xion-indexer-db + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://xion-indexer-node:3000 + ports: + - "3002" + networks: + - default + + xion-dashboard-app: + build: + context: xion-dashboard-app/ + args: + NETWORK_NAME: devnet + image: ghcr.io/burnt-labs/xion/xion-dashboard-app:latest + environment: + - VITE_NETWORK=devnet + - VITE_CHAIN_ID=xion-devnet-1 + - VITE_XION_API_URL=http://haproxy:1317 + - VITE_XION_RPC_URL=http://haproxy:26657 + - VITE_ABSTRAXION_API_URL=http://account-abstraction-api:3001 + - VITE_STYTCH_PUBLIC_TOKEN=${STYTCH_PUBLIC_TOKEN:-public-token-test-placeholder} + - VITE_NUMIA_TOKEN=${NUMIA_TOKEN:-placeholder} + - VITE_DEFAULT_INDEXER_URL=http://xion-indexer-graphql:3000 + - VITE_FEE_GRANTER_ADDRESS=${FEE_GRANTER_ADDRESS:-} + - VITE_DEFAULT_ACCOUNT_CONTRACT_CODE_ID=1 + ports: + - "3003" + depends_on: + - account-abstraction-api + networks: + - default + + xion-staking: + build: + context: xion-staking/ + image: ghcr.io/burnt-labs/xion/xion-staking:latest + environment: + - NEXT_PUBLIC_CHAIN_ID=xion-devnet-1 + ports: + - "3004" + depends_on: + xion: + condition: service_healthy + networks: + - default + networks: default: volumes: shared: + indexer-db: diff --git a/xion-dashboard-app b/xion-dashboard-app index 153b5a2..929807d 160000 --- a/xion-dashboard-app +++ b/xion-dashboard-app @@ -1 +1 @@ -Subproject commit 153b5a20f835baba5d01dcb1992374bf070d8fec +Subproject commit 929807d75b887fbd2cde5a31f6776ba8d31eebf6 diff --git a/xion-indexer b/xion-indexer new file mode 160000 index 0000000..4143bad --- /dev/null +++ b/xion-indexer @@ -0,0 +1 @@ +Subproject commit 4143bad0bf036c938633507e85c761275171a850 diff --git a/xion-staking b/xion-staking index c45398c..e5ee8d5 160000 --- a/xion-staking +++ b/xion-staking @@ -1 +1 @@ -Subproject commit c45398c0877addcf4fa33255030b75c67121520f +Subproject commit e5ee8d55d35be7abcc14a7b4c2c01d6072273f8d From 7dc17490ce860305245248c442b1013f736c2955 Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:26:04 +0000 Subject: [PATCH 04/16] feat: add IBC chain init scripts for Osmosis, Noble, and Hermes - Osmosis entrypoint: single validator, localosmo-1, fast blocks, API/gRPC enabled - Noble entrypoint: single validator, noble-devnet-1, USDC fiat-tokenfactory genesis config, auto-mint after start - Hermes config.toml: three-chain relay (xion, osmosis, noble) - Hermes entrypoint: waits for chains, imports keys, creates clients/connections/channels - HAProxy IBC config: osmosis RPC:26757/API:1417, noble RPC:26857/API:1517 - Shared relayer mnemonic across all chains for Hermes key import --- config/haproxy-ibc.cfg | 48 +++++++++ config/hermes/config.toml | 99 +++++++++++++++++++ scripts/init/hermes-entrypoint.sh | 69 +++++++++++++ scripts/init/noble-entrypoint.sh | 153 +++++++++++++++++++++++++++++ scripts/init/osmosis-entrypoint.sh | 87 ++++++++++++++++ 5 files changed, 456 insertions(+) create mode 100644 config/haproxy-ibc.cfg create mode 100644 config/hermes/config.toml create mode 100755 scripts/init/hermes-entrypoint.sh create mode 100755 scripts/init/noble-entrypoint.sh create mode 100755 scripts/init/osmosis-entrypoint.sh diff --git a/config/haproxy-ibc.cfg b/config/haproxy-ibc.cfg new file mode 100644 index 0000000..7a978af --- /dev/null +++ b/config/haproxy-ibc.cfg @@ -0,0 +1,48 @@ +# HAProxy IBC chain additions +# Append to or include from main haproxy.cfg + +# ─── Osmosis ──────────────────────────────── + +listen osmosis_rpc + bind *:26757 + mode http + http-response set-header Access-Control-Allow-Origin "*" + http-response set-header Access-Control-Allow-Methods "GET, POST, OPTIONS" + http-response set-header Access-Control-Allow-Headers "Content-Type" + server osmosis osmosis:26657 check resolvers default + +listen osmosis_api + bind *:1417 + mode http + http-response set-header Access-Control-Allow-Origin "*" + http-response set-header Access-Control-Allow-Methods "GET, POST, OPTIONS" + http-response set-header Access-Control-Allow-Headers "Content-Type" + server osmosis osmosis:1317 check resolvers default + +listen osmosis_grpc + bind *:9190 + mode tcp + server osmosis osmosis:9090 check resolvers default + +# ─── Noble ────────────────────────────────── + +listen noble_rpc + bind *:26857 + mode http + http-response set-header Access-Control-Allow-Origin "*" + http-response set-header Access-Control-Allow-Methods "GET, POST, OPTIONS" + http-response set-header Access-Control-Allow-Headers "Content-Type" + server noble noble:26657 check resolvers default + +listen noble_api + bind *:1517 + mode http + http-response set-header Access-Control-Allow-Origin "*" + http-response set-header Access-Control-Allow-Methods "GET, POST, OPTIONS" + http-response set-header Access-Control-Allow-Headers "Content-Type" + server noble noble:1317 check resolvers default + +listen noble_grpc + bind *:9290 + mode tcp + server noble noble:9090 check resolvers default diff --git a/config/hermes/config.toml b/config/hermes/config.toml new file mode 100644 index 0000000..fa8c6b7 --- /dev/null +++ b/config/hermes/config.toml @@ -0,0 +1,99 @@ +# Hermes IBC Relayer Configuration +# Three-chain relay: Xion ↔ Osmosis, Xion ↔ Noble + +[global] +log_level = 'info' + +[mode] +[mode.clients] +enabled = true +refresh = true +misbehaviour = false + +[mode.connections] +enabled = false + +[mode.channels] +enabled = false + +[mode.packets] +enabled = true +clear_interval = 100 +clear_on_start = true +tx_confirmation = false + +[rest] +enabled = false +host = '127.0.0.1' +port = 3000 + +[telemetry] +enabled = false +host = '127.0.0.1' +port = 3001 + +# ─── Xion ─────────────────────────────────── +[[chains]] +id = 'xion-devnet-1' +type = 'CosmosSdk' +rpc_addr = 'http://xion:26657' +grpc_addr = 'http://xion:9090' +event_source = { mode = 'push', url = 'ws://xion:26657/websocket', batch_delay = '500ms' } +account_prefix = 'xion' +key_name = 'relayer' +key_store_type = 'Test' +store_prefix = 'ibc' +default_gas = 400000 +max_gas = 3000000 +gas_price = { price = 0.0, denom = 'uxion' } +gas_multiplier = 1.3 +max_msg_num = 30 +max_tx_size = 180000 +clock_drift = '15s' +trusting_period = '14days' +trust_threshold = { numerator = '1', denominator = '3' } +address_type = { derivation = 'cosmos' } + +# ─── Osmosis ──────────────────────────────── +[[chains]] +id = 'localosmo-1' +type = 'CosmosSdk' +rpc_addr = 'http://osmosis:26657' +grpc_addr = 'http://osmosis:9090' +event_source = { mode = 'push', url = 'ws://osmosis:26657/websocket', batch_delay = '500ms' } +account_prefix = 'osmo' +key_name = 'relayer' +key_store_type = 'Test' +store_prefix = 'ibc' +default_gas = 400000 +max_gas = 3000000 +gas_price = { price = 0.0025, denom = 'uosmo' } +gas_multiplier = 1.3 +max_msg_num = 30 +max_tx_size = 180000 +clock_drift = '15s' +trusting_period = '14days' +trust_threshold = { numerator = '1', denominator = '3' } +address_type = { derivation = 'cosmos' } + +# ─── Noble ────────────────────────────────── +[[chains]] +id = 'noble-devnet-1' +type = 'CosmosSdk' +rpc_addr = 'http://noble:26657' +grpc_addr = 'http://noble:9090' +event_source = { mode = 'push', url = 'ws://noble:26657/websocket', batch_delay = '500ms' } +account_prefix = 'noble' +key_name = 'relayer' +key_store_type = 'Test' +store_prefix = 'ibc' +default_gas = 400000 +max_gas = 3000000 +gas_price = { price = 0.0, denom = 'ustake' } +gas_multiplier = 1.3 +max_msg_num = 30 +max_tx_size = 180000 +clock_drift = '15s' +trusting_period = '14days' +trust_threshold = { numerator = '1', denominator = '3' } +address_type = { derivation = 'cosmos' } diff --git a/scripts/init/hermes-entrypoint.sh b/scripts/init/hermes-entrypoint.sh new file mode 100755 index 0000000..1a91d72 --- /dev/null +++ b/scripts/init/hermes-entrypoint.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Hermes IBC relayer init script +# Waits for all chains, imports keys, creates clients/connections/channels, starts relaying + +# Shared relayer mnemonic (same as in osmosis/noble entrypoints) +RELAYER_MNEMONIC="opinion chunk knowledge hospital nature adjust candy struggle grain lemon virtual trigger fiber promise phone jelly name attitude arrow daring assist fossil liberty strong" + +HERMES_HOME="${HOME}/.hermes" +MNEMONIC_FILE="/tmp/relayer_mnemonic.txt" + +echo "${RELAYER_MNEMONIC}" > "${MNEMONIC_FILE}" + +# ── Wait for all chains to be healthy ── + +wait_for_chain() { + local name="$1" + local rpc="$2" + echo "Waiting for ${name} at ${rpc}..." + for i in $(seq 1 120); do + if curl -sf "${rpc}/status" > /dev/null 2>&1; then + local height=$(curl -sf "${rpc}/status" | jq -r '.result.sync_info.latest_block_height // "0"') + if [ "${height}" != "0" ] && [ "${height}" != "null" ] && [ "$(echo "${height}" | tr -d '[:space:]')" -gt 1 ] 2>/dev/null; then + echo "${name} is ready (block height: ${height})" + return 0 + fi + fi + sleep 5 + done + echo "ERROR: ${name} did not become ready in time" + exit 1 +} + +wait_for_chain "Xion" "http://xion:26657" +wait_for_chain "Osmosis" "http://osmosis:26657" +wait_for_chain "Noble" "http://noble:26657" + +echo "All chains are healthy!" + +# ── Import relayer keys ── + +echo "Importing relayer keys..." +hermes keys add --chain xion-devnet-1 --mnemonic-file "${MNEMONIC_FILE}" --overwrite 2>&1 || true +hermes keys add --chain localosmo-1 --mnemonic-file "${MNEMONIC_FILE}" --overwrite 2>&1 || true +hermes keys add --chain noble-devnet-1 --mnemonic-file "${MNEMONIC_FILE}" --overwrite 2>&1 || true + +rm -f "${MNEMONIC_FILE}" + +# ── Create clients, connections, and channels ── + +echo "Creating Xion ↔ Osmosis connection..." +hermes create client --host-chain xion-devnet-1 --reference-chain localosmo-1 +hermes create client --host-chain localosmo-1 --reference-chain xion-devnet-1 +hermes create connection --a-chain xion-devnet-1 --b-chain localosmo-1 +echo "Creating Xion ↔ Osmosis transfer channel (connection-0)..." +hermes create channel --a-chain xion-devnet-1 --a-connection connection-0 --a-port transfer --b-port transfer + +echo "Creating Xion ↔ Noble connection..." +hermes create client --host-chain xion-devnet-1 --reference-chain noble-devnet-1 +hermes create client --host-chain noble-devnet-1 --reference-chain xion-devnet-1 +hermes create connection --a-chain xion-devnet-1 --b-chain noble-devnet-1 +echo "Creating Xion ↔ Noble transfer channel (connection-1)..." +hermes create channel --a-chain xion-devnet-1 --a-connection connection-1 --a-port transfer --b-port transfer + +echo "IBC channels created successfully!" +echo "Starting Hermes relayer..." + +exec hermes start diff --git a/scripts/init/noble-entrypoint.sh b/scripts/init/noble-entrypoint.sh new file mode 100755 index 0000000..db1d45a --- /dev/null +++ b/scripts/init/noble-entrypoint.sh @@ -0,0 +1,153 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Noble single-validator init script for devnet +# Includes USDC (fiat-tokenfactory) genesis configuration + +CHAIN_ID="noble-devnet-1" +DAEMON_NAME="nobled" +DAEMON_HOME="${HOME}/.noble" +STAKING_DENOM="ustake" +GENESIS_AMOUNT="1000000000000" +GENTX_AMOUNT="500000000000" + +# Noble devnet mnemonic — different from xion and osmosis +MNEMONIC="camp creek youth spend option clinic entry ice front myth dress analyst merge work art gate challenge horror search gap fashion blanket ivory critic" + +# Relayer shared mnemonic (same across all chains for Hermes) +RELAYER_MNEMONIC="opinion chunk knowledge hospital nature adjust candy struggle grain lemon virtual trigger fiber promise phone jelly name attitude arrow daring assist fossil liberty strong" + +init_noble() { + if [ -f "${DAEMON_HOME}/config/genesis.json" ]; then + echo "Chain already initialized, starting..." + exec ${DAEMON_NAME} start --home "${DAEMON_HOME}" + fi + + echo "Initializing Noble chain ${CHAIN_ID}..." + ${DAEMON_NAME} init validator --chain-id "${CHAIN_ID}" --home "${DAEMON_HOME}" > /dev/null 2>&1 + + # Create validator key from mnemonic + echo "${MNEMONIC}" | ${DAEMON_NAME} keys add validator --keyring-backend test --recover --home "${DAEMON_HOME}" > /dev/null 2>&1 + VALADDR=$(${DAEMON_NAME} keys show validator -a --keyring-backend test --home "${DAEMON_HOME}") + echo "Validator address: ${VALADDR}" + + # Create minter key (for USDC minting) + ${DAEMON_NAME} keys add minter --keyring-backend test --home "${DAEMON_HOME}" > /dev/null 2>&1 + MINTER=$(${DAEMON_NAME} keys show minter -a --keyring-backend test --home "${DAEMON_HOME}") + echo "Minter address: ${MINTER}" + + # Create relayer key from shared mnemonic + echo "${RELAYER_MNEMONIC}" | ${DAEMON_NAME} keys add relayer --keyring-backend test --recover --home "${DAEMON_HOME}" > /dev/null 2>&1 + RELAYADDR=$(${DAEMON_NAME} keys show relayer -a --keyring-backend test --home "${DAEMON_HOME}") + echo "Relayer address: ${RELAYADDR}" + + # Fund accounts (staking denom) + ${DAEMON_NAME} genesis add-genesis-account "${VALADDR}" "${GENESIS_AMOUNT}${STAKING_DENOM}" --home "${DAEMON_HOME}" --keyring-backend test + ${DAEMON_NAME} genesis add-genesis-account "${MINTER}" "1000000${STAKING_DENOM}" --home "${DAEMON_HOME}" --keyring-backend test + ${DAEMON_NAME} genesis add-genesis-account "${RELAYADDR}" "10000000000${STAKING_DENOM}" --home "${DAEMON_HOME}" --keyring-backend test + + # Create gentx + ${DAEMON_NAME} genesis gentx validator "${GENTX_AMOUNT}${STAKING_DENOM}" \ + --chain-id "${CHAIN_ID}" \ + --keyring-backend test \ + --home "${DAEMON_HOME}" + + # Collect gentxs + ${DAEMON_NAME} genesis collect-gentxs --home "${DAEMON_HOME}" > /dev/null 2>&1 + + # ── Noble-specific genesis modifications (USDC / fiat-tokenfactory) ── + + GENESIS="${DAEMON_HOME}/config/genesis.json" + TMP="/tmp/genesis_tmp.json" + + # Set staking bond denom + jq '.app_state.staking.params.bond_denom = "ustake"' "${GENESIS}" > "${TMP}" && mv "${TMP}" "${GENESIS}" + + # Set authority owner + jq --arg addr "${VALADDR}" '.app_state.authority.owner = $addr' "${GENESIS}" > "${TMP}" && mv "${TMP}" "${GENESIS}" + + # USDC denom metadata + jq '.app_state.bank.denom_metadata += [{ + "description": "Circle USD Coin", + "denom_units": [ + {"denom": "uusdc", "exponent": 0, "aliases": ["microusdc"]}, + {"denom": "usdc", "exponent": 6} + ], + "base": "uusdc", + "display": "usdc", + "name": "Circle USD Coin", + "symbol": "USDC" + }]' "${GENESIS}" > "${TMP}" && mv "${TMP}" "${GENESIS}" + + # Fiat token factory — enable USDC minting + jq '.app_state["fiat-tokenfactory"].mintingDenom = {"denom": "uusdc"}' "${GENESIS}" > "${TMP}" && mv "${TMP}" "${GENESIS}" + jq '.app_state["fiat-tokenfactory"].paused.paused = false' "${GENESIS}" > "${TMP}" && mv "${TMP}" "${GENESIS}" + jq --arg addr "${VALADDR}" '.app_state["fiat-tokenfactory"].owner = {"address": $addr}' "${GENESIS}" > "${TMP}" && mv "${TMP}" "${GENESIS}" + jq --arg addr "${VALADDR}" '.app_state["fiat-tokenfactory"].masterMinter = {"address": $addr}' "${GENESIS}" > "${TMP}" && mv "${TMP}" "${GENESIS}" + jq --arg ctrl "${VALADDR}" --arg minter "${MINTER}" \ + '.app_state["fiat-tokenfactory"].minterControllerList = [{"controller": $ctrl, "minter": $minter}]' \ + "${GENESIS}" > "${TMP}" && mv "${TMP}" "${GENESIS}" + jq --arg minter "${MINTER}" \ + '.app_state["fiat-tokenfactory"].mintersList = [{"address": $minter, "allowance": {"denom": "uusdc", "amount": "1000000000000000"}}]' \ + "${GENESIS}" > "${TMP}" && mv "${TMP}" "${GENESIS}" + + # Replace "stake" with "ustake" in genesis (Noble default denom fix) + sed -i 's/"stake"/"ustake"/g' "${GENESIS}" + + # ── Config modifications ── + + CONFIG="${DAEMON_HOME}/config/config.toml" + APP_CONFIG="${DAEMON_HOME}/config/app.toml" + + # Fast block times + sed -i 's/^timeout_commit =.*$/timeout_commit = "1s"/' "${CONFIG}" + sed -i 's/^timeout_propose =.*$/timeout_propose = "1s"/' "${CONFIG}" + + # Allow external RPC connections + sed -i 's|laddr = "tcp://127.0.0.1:26657"|laddr = "tcp://0.0.0.0:26657"|' "${CONFIG}" + + # CORS + sed -i 's/cors_allowed_origins = \[\]/cors_allowed_origins = ["*"]/' "${CONFIG}" + + # Disable strict address book + sed -i 's/^addr_book_strict =.*$/addr_book_strict = false/' "${CONFIG}" + + # Enable API + sed -i '/^\[api\]$/,/^\[/ s/^enable = false/enable = true/' "${APP_CONFIG}" + sed -i 's|address = "tcp://localhost:1317"|address = "tcp://0.0.0.0:1317"|' "${APP_CONFIG}" + + # Enable gRPC + sed -i '/^\[grpc\]$/,/^\[/ s/^enable = false/enable = true/' "${APP_CONFIG}" + sed -i 's|address = "localhost:9090"|address = "0.0.0.0:9090"|' "${APP_CONFIG}" + + echo "Noble chain initialized successfully!" + + # Start chain, then mint USDC in background after chain is ready + mint_usdc_background & + exec ${DAEMON_NAME} start --home "${DAEMON_HOME}" +} + +mint_usdc_background() { + echo "Waiting for chain to produce blocks before minting USDC..." + sleep 15 + for i in $(seq 1 30); do + if ${DAEMON_NAME} status --home "${DAEMON_HOME}" 2>/dev/null | jq -e '.sync_info.latest_block_height | tonumber > 1' > /dev/null 2>&1; then + echo "Chain is producing blocks, minting USDC..." + ${DAEMON_NAME} tx fiat-tokenfactory mint "${MINTER}" 1000000000000uusdc \ + --from minter \ + --keyring-backend test \ + --home "${DAEMON_HOME}" \ + --chain-id "${CHAIN_ID}" \ + --gas auto \ + --gas-adjustment 1.5 \ + -y 2>&1 || echo "USDC mint failed, may need manual minting" + return + fi + sleep 5 + done + echo "WARNING: Chain did not produce blocks in time, USDC not minted" +} + +# Export MINTER for background function +export MINTER="" +init_noble diff --git a/scripts/init/osmosis-entrypoint.sh b/scripts/init/osmosis-entrypoint.sh new file mode 100755 index 0000000..5a729fd --- /dev/null +++ b/scripts/init/osmosis-entrypoint.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Osmosis single-validator init script for devnet +# Simplified from xion entrypoint.sh pattern + +CHAIN_ID="localosmo-1" +DAEMON_NAME="osmosisd" +DAEMON_HOME="${HOME}/.osmosisd" +DEFAULT_DENOM="uosmo" +GENESIS_AMOUNT="1000000000000" +GENTX_AMOUNT="500000000000" + +# Osmosis devnet mnemonic — different from xion +MNEMONIC="milk butter claim chair orient slow already effort champion feed meadow catalog worry kitchen risk flower surround cloud trip chapter vehicle economy voyage abstract" + +# Relayer shared mnemonic (same across all chains for Hermes) +RELAYER_MNEMONIC="opinion chunk knowledge hospital nature adjust candy struggle grain lemon virtual trigger fiber promise phone jelly name attitude arrow daring assist fossil liberty strong" + +init_osmosis() { + if [ -f "${DAEMON_HOME}/config/genesis.json" ]; then + echo "Chain already initialized, starting..." + exec ${DAEMON_NAME} start --home "${DAEMON_HOME}" + fi + + echo "Initializing Osmosis chain ${CHAIN_ID}..." + ${DAEMON_NAME} init validator --chain-id "${CHAIN_ID}" --home "${DAEMON_HOME}" --default-denom "${DEFAULT_DENOM}" > /dev/null 2>&1 + + # Create validator key from mnemonic + echo "${MNEMONIC}" | ${DAEMON_NAME} keys add validator --keyring-backend test --recover --home "${DAEMON_HOME}" > /dev/null 2>&1 + VALADDR=$(${DAEMON_NAME} keys show validator -a --keyring-backend test --home "${DAEMON_HOME}") + echo "Validator address: ${VALADDR}" + + # Create relayer key from shared mnemonic + echo "${RELAYER_MNEMONIC}" | ${DAEMON_NAME} keys add relayer --keyring-backend test --recover --home "${DAEMON_HOME}" > /dev/null 2>&1 + RELAYADDR=$(${DAEMON_NAME} keys show relayer -a --keyring-backend test --home "${DAEMON_HOME}") + echo "Relayer address: ${RELAYADDR}" + + # Create test account + ${DAEMON_NAME} keys add test-account --keyring-backend test --home "${DAEMON_HOME}" > /dev/null 2>&1 + TESTADDR=$(${DAEMON_NAME} keys show test-account -a --keyring-backend test --home "${DAEMON_HOME}") + + # Fund accounts in genesis + ${DAEMON_NAME} genesis add-genesis-account "${VALADDR}" "${GENESIS_AMOUNT}${DEFAULT_DENOM}" --home "${DAEMON_HOME}" --keyring-backend test + ${DAEMON_NAME} genesis add-genesis-account "${RELAYADDR}" "10000000000${DEFAULT_DENOM}" --home "${DAEMON_HOME}" --keyring-backend test + ${DAEMON_NAME} genesis add-genesis-account "${TESTADDR}" "10000000000${DEFAULT_DENOM}" --home "${DAEMON_HOME}" --keyring-backend test + + # Create gentx + ${DAEMON_NAME} genesis gentx validator "${GENTX_AMOUNT}${DEFAULT_DENOM}" \ + --chain-id "${CHAIN_ID}" \ + --keyring-backend test \ + --home "${DAEMON_HOME}" + + # Collect gentxs + ${DAEMON_NAME} genesis collect-gentxs --home "${DAEMON_HOME}" > /dev/null 2>&1 + + # ── Config modifications ── + + CONFIG="${DAEMON_HOME}/config/config.toml" + APP_CONFIG="${DAEMON_HOME}/config/app.toml" + + # Fast block times + sed -i 's/^timeout_commit =.*$/timeout_commit = "1s"/' "${CONFIG}" + sed -i 's/^timeout_propose =.*$/timeout_propose = "1s"/' "${CONFIG}" + + # Allow external RPC connections + sed -i 's|laddr = "tcp://127.0.0.1:26657"|laddr = "tcp://0.0.0.0:26657"|' "${CONFIG}" + + # CORS + sed -i 's/cors_allowed_origins = \[\]/cors_allowed_origins = ["*"]/' "${CONFIG}" + + # Disable strict address book + sed -i 's/^addr_book_strict =.*$/addr_book_strict = false/' "${CONFIG}" + + # Enable API + sed -i '/^\[api\]$/,/^\[/ s/^enable = false/enable = true/' "${APP_CONFIG}" + sed -i 's|address = "tcp://localhost:1317"|address = "tcp://0.0.0.0:1317"|' "${APP_CONFIG}" + + # Enable gRPC + sed -i '/^\[grpc\]$/,/^\[/ s/^enable = false/enable = true/' "${APP_CONFIG}" + sed -i 's|address = "localhost:9090"|address = "0.0.0.0:9090"|' "${APP_CONFIG}" + + echo "Osmosis chain initialized successfully!" + exec ${DAEMON_NAME} start --home "${DAEMON_HOME}" +} + +init_osmosis From 391f51b67c86e46d307e788a901c983c4a77ca93 Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:26:04 +0000 Subject: [PATCH 05/16] feat: complete docker-compose with all services, profiles, IBC, HAProxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Services (25+): - Core: xion (3 validators), haproxy, explorer, faucet - Apps: AA API, dashboard, staking, dev-portal, indexer (SubQuery), assets - OAuth: oauth3, oauth2-api-service, oauth2-clients-dashboard - ZK: zk-email-backend, zk-email-prover, zk-email-worker - IBC: osmosis (v28.0.0), noble (v11.3.0), hermes relayer (v1.12.0) - Infra: postgresql Profiles: core, apps, oauth, zk, ibc, full HAProxy: routes for all 20+ backends Hermes: config for xion↔osmosis, xion↔noble IBC .gitmodules: 17 submodules (7 new) .env.example, Makefile, README updated --- .env | 2 + .env.example | 53 +++ .gitmodules | 30 +- Makefile | 51 ++- README.md | 148 +++----- config/haproxy.cfg | 106 +++++- docker-compose.yml | 582 ++++++++++++++++++++++++++---- oauth2-api-service/.gitkeep | 0 oauth2-clients-dashboard/.gitkeep | 0 oauth3/.gitkeep | 0 xion-indexer-proxy/.gitkeep | 0 zk-email-backend/.gitkeep | 0 zk-email-prover/.gitkeep | 0 zk-email-worker/.gitkeep | 0 14 files changed, 785 insertions(+), 187 deletions(-) create mode 100644 .env.example create mode 100644 oauth2-api-service/.gitkeep create mode 100644 oauth2-clients-dashboard/.gitkeep create mode 100644 oauth3/.gitkeep create mode 100644 xion-indexer-proxy/.gitkeep create mode 100644 zk-email-backend/.gitkeep create mode 100644 zk-email-prover/.gitkeep create mode 100644 zk-email-worker/.gitkeep diff --git a/.env b/.env index 089977c..fc2bae7 100644 --- a/.env +++ b/.env @@ -33,3 +33,5 @@ MODIFY_GENESIS_JQ=' ' + +RELAYER_MNEMONIC="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art" diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..b87ba33 --- /dev/null +++ b/.env.example @@ -0,0 +1,53 @@ +# ═══════════════════════════════════════════════════════════════════════════ +# Xion Devnet — Environment Variables +# ═══════════════════════════════════════════════════════════════════════════ + +# --- Xion Chain --- +XIOND_VERSION="28.1.0" +CHAIN_ID="xion-devnet-1" +DAEMON_HOME="/home/xiond/.xiond" +DAEMON_NAME="xiond" +DEFAULT_DENOM="uxion" +DENOM_METADATA_NAME="xion" +GENESIS_AMOUNT="1000000000000" +GENTX_AMOUNT="1000000" +NUM_VALIDATORS=3 + +# Devnet mnemonic (NOT SENSITIVE — do not use in production) +MNEMONIC="decorate corn happy degree artist trouble color mountain shadow hazard canal zone hunt unfold deny glove famous area arrow cup under sadness salute item" +ABSTRAXION_ADDRESS="xion1e2fuwe3uhq8zd9nkkk876nawrwdulgv460vzg7" + +# --- Source Chain (genesis import) --- +SOURCE_CHAIN_ID="xion-testnet-2" +SOURCE_CHAIN_RPC="https://rpc.xion-testnet-2.burnt.com:443" +SOURCE_CHAIN_API="https://api.xion-testnet-2.burnt.com:443" +SOURCE_CHAIN_CODE_IDS="1 1260" + +# --- Faucet --- +FAUCET_ACCOUNTS="10" +FAUCET_AMOUNT="100000000" + +# --- Genesis Modifications --- +MODIFY_GENESIS_JQ=' + .app_state.gov.params.expedited_voting_period = "0h1m0s" | + .app_state.feeabs.epochs = [] | + .app_state.feeabs.params.native_ibced_in_osmosis = "" | + .app_state.feeabs.params.chain_name = "" +' + +# --- Postgres --- +POSTGRES_USER=postgres +POSTGRES_PASSWORD=postgres +POSTGRES_DB=postgres + +# --- Indexer --- +SUB_COMMAND=forceClean + +# --- Dashboard --- +STYTCH_PUBLIC_TOKEN=public-token-test-placeholder +NUMIA_TOKEN=placeholder +FEE_GRANTER_ADDRESS= +ZKEMAIL_FLAG=false + +# --- IBC Relayer --- +RELAYER_MNEMONIC="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art" diff --git a/.gitmodules b/.gitmodules index 117b302..d8645ca 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,7 +9,7 @@ [submodule "xion-explorer"] path = xion-explorer url = https://github.com/burnt-labs/xion-explorer.git - branch = xion/mainnet + branch = chore/devnet [submodule "xion-faucet"] path = xion-faucet url = https://github.com/burnt-labs/xion-faucet.git @@ -30,7 +30,35 @@ path = xion-indexer url = https://github.com/burnt-labs/xion-indexer.git branch = chore/devnet +[submodule "xion-indexer-proxy"] + path = xion-indexer-proxy + url = https://github.com/burnt-labs/xion-indexer-proxy.git + branch = chore/devnet [submodule "account-abstraction-api"] path = account-abstraction-api url = https://github.com/burnt-labs/account-abstraction-api.git branch = chore/devnet +[submodule "oauth3"] + path = oauth3 + url = https://github.com/burnt-labs/oauth3.git + branch = chore/devnet +[submodule "oauth2-api-service"] + path = oauth2-api-service + url = https://github.com/burnt-labs/oauth2-api-service.git + branch = chore/devnet +[submodule "oauth2-clients-dashboard"] + path = oauth2-clients-dashboard + url = https://github.com/burnt-labs/oauth2-clients-dashboard.git + branch = chore/devnet +[submodule "zk-email-backend"] + path = zk-email-backend + url = https://github.com/burnt-labs/zk-email-backend.git + branch = chore/devnet +[submodule "zk-email-prover"] + path = zk-email-prover + url = https://github.com/burnt-labs/zk-email-prover.git + branch = chore/devnet +[submodule "zk-email-worker"] + path = zk-email-worker + url = https://github.com/burnt-labs/zk-email-worker.git + branch = chore/devnet diff --git a/Makefile b/Makefile index abe849d..ab37f20 100644 --- a/Makefile +++ b/Makefile @@ -1,24 +1,53 @@ -singleton: - . .env && ./scripts/docker-run.sh +# Xion Devnet — Makefile +PROFILE ?= core +COMMIT ?= $(shell cd ./xion && git rev-parse --short HEAD 2>/dev/null || echo "unknown") + +.PHONY: build build-no-cache start stop down clean purge logs status singleton core apps oauth zk ibc full build: - COMMIT=$$(cd ./xion && git rev-parse --short HEAD) docker compose build --pull + COMMIT=$(COMMIT) docker compose --profile $(PROFILE) build --pull build-no-cache: - COMMIT=$$(cd ./xion && git rev-parse --short HEAD) docker compose build --pull --no-cache + COMMIT=$(COMMIT) docker compose --profile $(PROFILE) build --pull --no-cache -start: - docker compose up -d +start up: + docker compose --profile $(PROFILE) up -d stop: - docker compose stop + docker compose --profile $(PROFILE) stop down: - docker compose down + docker compose --profile $(PROFILE) down clean: - docker compose rm -f -s -v + docker compose --profile $(PROFILE) rm -f -s -v purge: - docker compose rm -f -s -v - docker volume rm -f devnet_shared + docker compose --profile $(PROFILE) down -v --remove-orphans + +logs: + docker compose --profile $(PROFILE) logs -f + +status: + docker compose --profile $(PROFILE) ps + +core: + $(MAKE) start PROFILE=core + +apps: + $(MAKE) start PROFILE=apps + +oauth: + $(MAKE) start PROFILE=oauth + +zk: + $(MAKE) start PROFILE=zk + +ibc: + $(MAKE) start PROFILE=ibc + +full: + $(MAKE) start PROFILE=full + +singleton: + . .env && ./scripts/docker-run.sh diff --git a/README.md b/README.md index f55c5e0..eb9dcaf 100644 --- a/README.md +++ b/README.md @@ -1,113 +1,57 @@ -# Xion Devnet +# Xion Devnet — Full Stack -Xion Devnet is a multi-validator sandbox environment orchestrated with Docker Compose for local development and testing. - -## Prerequisites - -- [Docker](https://www.docker.com/) (version 20.10 or higher) -- [Docker Compose](https://github.com/docker/compose) (version 2.0 or higher) -- [Make](https://www.gnu.org/software/make/) (for using Makefile commands) +Run the entire Xion ecosystem locally with Docker Compose. ## Quick Start -The easiest way to get started is using the provided Makefile commands: - -```sh -# Build devnet images with commit ID -make build - -# Start devnet in background -make start - -# Stop devnet (preserves state) -make stop - -# Stop and remove containers -make down - -# Clean up containers -make clean - -# Complete purge (removes containers and shared volume) -make purge - -# Start singleton validator from .env configuration -make singleton +```bash +git clone --recurse-submodules -b chore/devnet-v28 https://github.com/burnt-labs/devnet.git +cd devnet +cp .env.example .env +make core # chain + haproxy + explorer + faucet +make full # everything ``` -## Manual Docker Compose Commands - -If you prefer to use Docker Compose directly: - -```sh -# Build images with commit ID -COMMIT=$(cd ./xion && git rev-parse --short HEAD) docker compose build --pull --no-cache - -# Start devnet -docker compose up -d - -# Stop devnet (preserves blockchain state) -docker compose stop - -# Stop and remove containers -docker compose down - -# View logs -docker compose logs -f - -# Complete cleanup and reset -docker compose rm -f -s -v -docker volume rm -f devnet_shared - -# Restart from previous height -docker compose start +## Profiles + +| Profile | Services | +|---------|----------| +| `core` | Xion (3 validators), HAProxy, Explorer, Faucet | +| `apps` | Core + AA API, Dashboard, Staking, Dev Portal, Indexer, Assets | +| `oauth` | Apps + OAuth3, OAuth2 API, OAuth2 Clients Dashboard | +| `zk` | Apps + ZK Email Backend, Prover, Worker | +| `ibc` | Core + Osmosis, Noble, Hermes relayer | +| `full` | Everything | + +## Ports + +| Port | Service | Port | Service | +|------|---------|------|---------| +| 1317 | Xion REST | 8001 | Indexer Proxy | +| 9090 | Xion gRPC | 8002 | OAuth2 API | +| 26657 | Xion RPC | 8003 | OAuth2 Clients | +| 3000 | Faucet | 8080 | OAuth3 | +| 3001 | AA API | 8081 | ZK Email Prover | +| 3002 | Indexer GraphQL | 8082 | ZK Email Worker | +| 3003 | Developer Portal | 8788 | Staking | +| 4173 | Dashboard | 26757 | Osmosis RPC | +| 5173 | Explorer | 26857 | Noble RPC | +| 8444 | HAProxy Stats | 9190/9290 | Osmosis/Noble gRPC | + +## Commands + +```bash +make build PROFILE=apps # Build images +make start PROFILE=apps # Start +make logs PROFILE=apps # Follow logs +make status # Container status +make purge # Remove everything ``` -## Configuration Options - -- **NUM_VALIDATORS**: Number of validator nodes (default: 3) -- **XIOND_VERSION**: Version tag for the xion docker image (default: latest) -- **COMMIT**: Git commit hash passed to build (automatically set by Makefile) -- **DAEMON_NAME**: Name of the daemon process (configured in .env) - -## Network Information - -Once running, the devnet exposes the following services through HAProxy: - -- **RPC Endpoint**: `http://localhost:26657` -- **API Endpoint**: `http://localhost:1317` -- **gRPC Endpoint**: `http://localhost:9090` -- **Xion Explorer**: `http://localhost:5173` -- **Xion Faucet**: `http://localhost:3000` -- **Additional RPC**: `http://localhost:26658` +## IBC -The setup includes: - -- **Xion validators**: Configurable number of validator nodes (default: 3) -- **HAProxy**: Load balancer and reverse proxy -- **Xion Explorer**: Web interface for blockchain exploration -- **Xion Faucet**: Token distribution service - -## Submodules - -This devnet environment includes several Xion ecosystem components as git submodules: - -- **[xion](https://github.com/burnt-labs/xion)** - Core Xion blockchain node and validator software -- **[xion-explorer](https://github.com/burnt-labs/xion-explorer)** - Web-based blockchain explorer for viewing transactions and blocks -- **[xion-faucet](https://github.com/burnt-labs/xion-faucet)** - Token distribution service for testnet XION tokens -- **[xion-staking](https://github.com/burnt-labs/xion-staking)** - Staking interface for validators and delegators -- **[xion-assets](https://github.com/burnt-labs/xion-assets)** - Static assets and branding resources - -To update all submodules to their latest commits: - -```sh -git submodule update --remote --recursive -``` +The `ibc` profile starts Osmosis (v28.0.0) and Noble (v11.3.0) with a Hermes relayer (v1.12.0). Channels are auto-created for `transfer` on both pairs. Noble includes USDC minting via `fiat-tokenfactory`. -## Troubleshooting +## Environment -- **Port conflicts**: Ensure ports 26657, 1317, 9090, 5173, and 3000 are available -- **Storage issues**: Use `make purge` to reset blockchain state and volumes -- **Build failures**: Try `make build` to rebuild images with commit ID -- **Permission errors**: Ensure Docker daemon is running and user has permissions -- **Service startup**: Check `docker compose logs -f` for detailed error messages +See `.env.example` for all variables. Key ones: `XIOND_VERSION`, `NUM_VALIDATORS`, `RELAYER_MNEMONIC`, `STYTCH_PUBLIC_TOKEN`, `FEE_GRANTER_ADDRESS`. diff --git a/config/haproxy.cfg b/config/haproxy.cfg index 4b93cd6..99e8b15 100644 --- a/config/haproxy.cfg +++ b/config/haproxy.cfg @@ -1,6 +1,5 @@ global log stdout format raw daemon debug - #stats socket /var/lib/haproxy/haproxy.sock level admin defaults log global @@ -9,6 +8,17 @@ defaults timeout client 30s timeout server 30s +resolvers default + nameserver dns 127.0.0.11:53 + resolve_retries 3 + timeout resolve 1s + timeout retry 1s + hold other 10s + hold refused 10s + hold nx 10s + hold timeout 10s + hold valid 10s + frontend stats bind *:8444 mode http @@ -16,12 +26,16 @@ frontend stats stats uri / stats refresh 10s +# ═══════════════════════════════════════════════════════════════════════════ +# CORE — Xion Chain +# ═══════════════════════════════════════════════════════════════════════════ + listen rest bind *:1317 + mode http http-response set-header Access-Control-Allow-Origin "*" http-response set-header Access-Control-Allow-Methods "GET, POST, OPTIONS" http-response set-header Access-Control-Allow-Headers "Content-Type" - mode http server-template s 10 xion:1317 check init-addr last,none resolvers default listen grpc @@ -42,6 +56,10 @@ listen client mode tcp server-template s 10 xion:26658 check init-addr last,none resolvers default +# ═══════════════════════════════════════════════════════════════════════════ +# CORE — Faucet & Explorer +# ═══════════════════════════════════════════════════════════════════════════ + listen faucet bind *:3000 mode http @@ -52,22 +70,98 @@ listen explorer mode http server xion-explorer xion-explorer:5173 check resolvers default +# ═══════════════════════════════════════════════════════════════════════════ +# APPS +# ═══════════════════════════════════════════════════════════════════════════ + listen aa-api bind *:3001 mode http - server account-abstraction-api account-abstraction-api:3000 check resolvers default + server account-abstraction-api account-abstraction-api:3001 check resolvers default listen indexer bind *:3002 mode http server xion-indexer-graphql xion-indexer-graphql:3000 check resolvers default -listen dashboard +listen developer-portal bind *:3003 mode http - server xion-dashboard-app xion-dashboard-app:3000 check resolvers default + server xion-developer-portal xion-developer-portal:3002 check resolvers default + +listen dashboard + bind *:4173 + mode http + server xion-dashboard-app xion-dashboard-app:4173 check resolvers default + +listen indexer-proxy + bind *:8001 + mode http + server xion-indexer-proxy xion-indexer-proxy:8001 check resolvers default listen staking + bind *:8788 + mode http + server xion-staking xion-staking:8788 check resolvers default + +listen assets bind *:3004 mode http - server xion-staking xion-staking:3000 check resolvers default + server xion-assets xion-assets:3003 check resolvers default + +# ═══════════════════════════════════════════════════════════════════════════ +# OAUTH +# ═══════════════════════════════════════════════════════════════════════════ + +listen oauth3 + bind *:8080 + mode http + server oauth3 oauth3:8080 check resolvers default + +listen oauth2-api + bind *:8002 + mode http + server oauth2-api-service oauth2-api-service:8002 check resolvers default + +listen oauth2-clients + bind *:8003 + mode http + server oauth2-clients-dashboard oauth2-clients-dashboard:8003 check resolvers default + +# ═══════════════════════════════════════════════════════════════════════════ +# ZK +# ═══════════════════════════════════════════════════════════════════════════ + +listen zk-email-prover + bind *:8081 + mode http + server zk-email-prover zk-email-prover:8081 check resolvers default + +listen zk-email-worker + bind *:8082 + mode http + server zk-email-worker zk-email-worker:8082 check resolvers default + +# ═══════════════════════════════════════════════════════════════════════════ +# IBC — Osmosis & Noble +# ═══════════════════════════════════════════════════════════════════════════ + +listen osmosis-rpc + bind *:26757 + mode http + server osmosis osmosis:26657 check resolvers default + +listen osmosis-grpc + bind *:9190 + mode tcp + server osmosis osmosis:9090 check resolvers default + +listen noble-rpc + bind *:26857 + mode http + server noble noble:26657 check resolvers default + +listen noble-grpc + bind *:9290 + mode tcp + server noble noble:9090 check resolvers default diff --git a/docker-compose.yml b/docker-compose.yml index cafddc1..3fff5dd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,69 +1,109 @@ +############################################################################### +# Xion Devnet — Full Stack Docker Compose +# +# Profiles: +# core — xion (3 validators) + haproxy + explorer + faucet +# apps — core + AA API + dashboard + staking + dev-portal + indexer + assets +# oauth — apps + oauth3 + oauth2-api-service + oauth2-clients-dashboard +# zk — apps + zk-email-backend + zk-email-prover + zk-email-worker +# ibc — core + osmosis + noble + hermes relayer +# full — everything +# +# Usage: +# docker compose --profile core up -d +# docker compose --profile full up -d +############################################################################### + services: + + # ═══════════════════════════════════════════════════════════════════════════ + # CORE PROFILE + # ═══════════════════════════════════════════════════════════════════════════ + haproxy: image: haproxy:3.2-alpine - command: > - haproxy -f /usr/local/etc/haproxy/haproxy.cfg + profiles: ["core", "apps", "oauth", "zk", "ibc", "full"] + command: haproxy -f /usr/local/etc/haproxy/haproxy.cfg depends_on: - xion - networks: - - default - ports: - - 1317:1317 - - 3000:3000 - - 3001:3001 - - 3002:3002 - - 3003:3003 - - 3004:3004 - - 5173:5173 - - 9090:9090 - - 26657:26657 - - 26658:26658 + ports: + - "1317:1317" # Xion REST/LCD + - "9090:9090" # Xion gRPC + - "26657:26657" # Xion RPC + - "26658:26658" # Xion P2P + - "3000:3000" # Faucet + - "3001:3001" # AA API + - "3002:3002" # Indexer GraphQL + - "3003:3003" # Developer Portal + - "4173:4173" # Dashboard + - "5173:5173" # Explorer + - "8001:8001" # Indexer Proxy + - "8002:8002" # OAuth2 API Service + - "8003:8003" # OAuth2 Clients Dashboard + - "8080:8080" # OAuth3 + - "8081:8081" # ZK Email Prover + - "8082:8082" # ZK Email Worker + - "8788:8788" # Staking + - "8444:8444" # HAProxy stats + - "26757:26757" # Osmosis RPC + - "9190:9190" # Osmosis gRPC + - "26857:26857" # Noble RPC + - "9290:9290" # Noble gRPC volumes: - ./config/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro + healthcheck: + test: ["CMD-SHELL", "haproxy -c -f /usr/local/etc/haproxy/haproxy.cfg"] + interval: 10s + timeout: 5s + retries: 3 + networks: + - devnet xion: image: ghcr.io/burnt-labs/xion/xion:${XIOND_VERSION:-latest} + profiles: ["core", "apps", "oauth", "zk", "ibc", "full"] build: context: ./xion args: - VERSION=${XIOND_VERSION} - COMMIT=${COMMIT} - command: > - /usr/bin/cosmovisor run start \ - --api.address tcp://0.0.0.0:1317 \ - --api.enable true \ - --api.enabled-unsafe-cors true \ - --api.swagger true \ - --grpc.enable true \ - --grpc.address 0.0.0.0:9090 \ - --grpc-web.enable \ - --minimum-gas-prices 0.001uxion \ - --rpc.laddr tcp://0.0.0.0:26657 entrypoint: /home/xiond/init/entrypoint.sh + command: > + /usr/bin/cosmovisor run start + --api.address tcp://0.0.0.0:1317 + --api.enable true + --api.enabled-unsafe-cors true + --api.swagger true + --grpc.enable true + --grpc.address 0.0.0.0:9090 + --grpc-web.enable + --minimum-gas-prices 0.001uxion + --rpc.laddr tcp://0.0.0.0:26657 deploy: replicas: ${NUM_VALIDATORS:-3} env_file: - .env ports: - - 1317 - - 9090 - - 26656 - - 26657 + - "1317" + - "9090" + - "26656" + - "26657" healthcheck: - test: ["CMD-SHELL", "curl http://localhost:26657/status"] + test: ["CMD-SHELL", "curl -sf http://localhost:26657/status"] interval: 5s timeout: 5s - retries: 5 + retries: 10 user: root working_dir: /home/${DAEMON_NAME} - networks: - - default volumes: - /home/${DAEMON_NAME} - shared:/home/${DAEMON_NAME}/.shared - ./scripts/init:/home/${DAEMON_NAME}/init + networks: + - devnet xion-explorer: + profiles: ["core", "apps", "oauth", "zk", "ibc", "full"] build: context: xion-explorer/ args: @@ -71,10 +111,16 @@ services: image: ghcr.io/burnt-labs/xion/xion-explorer:latest ports: - "5173" + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:5173/ || exit 1"] + interval: 15s + timeout: 5s + retries: 5 networks: - - default + - devnet xion-faucet: + profiles: ["core", "apps", "oauth", "zk", "ibc", "full"] build: context: xion-faucet/ args: @@ -84,12 +130,20 @@ services: - ./xion-faucet/.env.example ports: - "3000" + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:3000/ || exit 1"] + interval: 15s + timeout: 5s + retries: 5 networks: - - default + - devnet - # === Core Apps (Phase 2) === + # ═══════════════════════════════════════════════════════════════════════════ + # APPS PROFILE + # ═══════════════════════════════════════════════════════════════════════════ account-abstraction-api: + profiles: ["apps", "oauth", "zk", "full"] build: context: account-abstraction-api/ image: ghcr.io/burnt-labs/xion/account-abstraction-api:latest @@ -99,43 +153,53 @@ services: - XION_GRPC_URL=haproxy:9090 - CHAIN_ID=xion-devnet-1 ports: - - "3000" + - "3001" depends_on: xion: condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:3001/health || exit 1"] + interval: 15s + timeout: 5s + retries: 5 networks: - - default + - devnet + + # --- Indexer (SubQuery) --- - xion-indexer-db: + postgresql: image: postgres:16-alpine + profiles: ["apps", "oauth", "zk", "full"] environment: - POSTGRES_PASSWORD: postgres - POSTGRES_DB: postgres + POSTGRES_USER: ${POSTGRES_USER:-postgres} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres} + POSTGRES_DB: ${POSTGRES_DB:-postgres} ports: - "5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s - retries: 5 + retries: 10 volumes: - - indexer-db:/var/lib/postgresql/data + - postgres-data:/var/lib/postgresql/data networks: - - default + - devnet xion-indexer-node: image: subquerynetwork/subql-node-cosmos:v3.11.2 + profiles: ["apps", "oauth", "zk", "full"] depends_on: - xion-indexer-db: + postgresql: condition: service_healthy xion: condition: service_healthy restart: always environment: - DB_USER: postgres - DB_PASS: postgres - DB_DATABASE: postgres - DB_HOST: xion-indexer-db + DB_USER: ${POSTGRES_USER:-postgres} + DB_PASS: ${POSTGRES_PASSWORD:-postgres} + DB_DATABASE: ${POSTGRES_DB:-postgres} + DB_HOST: postgresql DB_PORT: 5432 volumes: - ./xion-indexer:/app @@ -145,37 +209,69 @@ services: - --db-schema=app - --unsafe healthcheck: - test: ["CMD", "curl", "-f", "http://xion-indexer-node:3000/ready"] - interval: 3s + test: ["CMD-SHELL", "curl -sf http://localhost:3000/ready || exit 1"] + interval: 10s timeout: 5s - retries: 10 + retries: 15 networks: - - default + - devnet xion-indexer-graphql: image: subquerynetwork/subql-query:latest + profiles: ["apps", "oauth", "zk", "full"] depends_on: - xion-indexer-db: + postgresql: condition: service_healthy xion-indexer-node: condition: service_healthy restart: always environment: - DB_USER: postgres - DB_PASS: postgres - DB_DATABASE: postgres - DB_HOST: xion-indexer-db + DB_USER: ${POSTGRES_USER:-postgres} + DB_PASS: ${POSTGRES_PASSWORD:-postgres} + DB_DATABASE: ${POSTGRES_DB:-postgres} + DB_HOST: postgresql DB_PORT: 5432 command: - --name=app - --playground - --indexer=http://xion-indexer-node:3000 ports: - - "3002" + - "3000" + healthcheck: + test: ["CMD-SHELL", "curl -sf http://localhost:3000/ || exit 1"] + interval: 10s + timeout: 5s + retries: 10 networks: - - default + - devnet + + xion-indexer-proxy: + profiles: ["apps", "oauth", "zk", "full"] + build: + context: xion-indexer-proxy/ + dockerfile: Dockerfile + image: ghcr.io/burnt-labs/xion/xion-indexer-proxy:latest + environment: + - UPSTREAM_HOST=http://haproxy:1317 + - CHAIN_ID=xion-devnet-1 + - INDEXER_GRAPHQL_URL=http://xion-indexer-graphql:3000 + ports: + - "8001" + depends_on: + xion-indexer-graphql: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:8001/ || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + networks: + - devnet + + # --- Dashboard (Primary App) --- xion-dashboard-app: + profiles: ["apps", "oauth", "zk", "full"] build: context: xion-dashboard-app/ args: @@ -192,30 +288,382 @@ services: - VITE_DEFAULT_INDEXER_URL=http://xion-indexer-graphql:3000 - VITE_FEE_GRANTER_ADDRESS=${FEE_GRANTER_ADDRESS:-} - VITE_DEFAULT_ACCOUNT_CONTRACT_CODE_ID=1 + - VITE_ZKEMAIL_FLAG=${ZKEMAIL_FLAG:-false} + - VITE_ZKEMAIL_BACKEND_URL=http://zk-email-backend:4500 ports: - - "3003" + - "4173" depends_on: - account-abstraction-api + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:4173/ || exit 1"] + interval: 15s + timeout: 5s + retries: 5 networks: - - default + - devnet + + # --- Staking --- xion-staking: + profiles: ["apps", "oauth", "zk", "full"] build: context: xion-staking/ + dockerfile: Dockerfile image: ghcr.io/burnt-labs/xion/xion-staking:latest environment: - NEXT_PUBLIC_CHAIN_ID=xion-devnet-1 + - NEXT_PUBLIC_RPC_URL=http://haproxy:26657 + - NEXT_PUBLIC_API_URL=http://haproxy:1317 + ports: + - "8788" + depends_on: + xion: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:8788/ || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + networks: + - devnet + + # --- Developer Portal --- + + xion-developer-portal: + profiles: ["apps", "oauth", "zk", "full"] + build: + context: xion-developer-portal/ + dockerfile: Dockerfile + image: ghcr.io/burnt-labs/xion/xion-developer-portal:latest + environment: + - VITE_CHAIN_ID=xion-devnet-1 + - VITE_RPC_URL=http://haproxy:26657 + - VITE_API_URL=http://haproxy:1317 + ports: + - "3002" + depends_on: + xion: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:3002/ || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + networks: + - devnet + + # --- Assets --- + + xion-assets: + profiles: ["apps", "oauth", "zk", "full"] + build: + context: xion-assets/ + dockerfile: Dockerfile + image: ghcr.io/burnt-labs/xion/xion-assets:latest + environment: + - VITE_CHAIN_ID=xion-devnet-1 + ports: + - "3003" + depends_on: + xion: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:3003/ || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + networks: + - devnet + + # ═══════════════════════════════════════════════════════════════════════════ + # OAUTH PROFILE + # ═══════════════════════════════════════════════════════════════════════════ + + oauth3: + profiles: ["oauth", "full"] + build: + context: oauth3/ + dockerfile: Dockerfile + image: ghcr.io/burnt-labs/xion/oauth3:latest + environment: + - DATABASE_URL=sqlite:///app/data/oauth3.db + - RUST_LOG=info,oauth3=debug + - XION_RPC_URL=http://haproxy:26657 + - XION_API_URL=http://haproxy:1317 + - CHAIN_ID=xion-devnet-1 + ports: + - "8080" + volumes: + - oauth3-data:/app/data + depends_on: + xion: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:8080/health || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + networks: + - devnet + + oauth2-api-service: + profiles: ["oauth", "full"] + build: + context: oauth2-api-service/ + dockerfile: Dockerfile + image: ghcr.io/burnt-labs/xion/oauth2-api-service:latest + environment: + - OAUTH3_URL=http://oauth3:8080 + - XION_RPC_URL=http://haproxy:26657 + - CHAIN_ID=xion-devnet-1 + ports: + - "8002" + depends_on: + - oauth3 + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:8002/ || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + networks: + - devnet + + oauth2-clients-dashboard: + profiles: ["oauth", "full"] + build: + context: oauth2-clients-dashboard/ + dockerfile: Dockerfile + image: ghcr.io/burnt-labs/xion/oauth2-clients-dashboard:latest + environment: + - VITE_OAUTH2_API_URL=http://oauth2-api-service:8002 + - VITE_CHAIN_ID=xion-devnet-1 + ports: + - "8003" + depends_on: + - oauth2-api-service + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:8003/ || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + networks: + - devnet + + # ═══════════════════════════════════════════════════════════════════════════ + # ZK PROFILE + # ═══════════════════════════════════════════════════════════════════════════ + + zk-email-backend: + profiles: ["zk", "full"] + build: + context: zk-email-backend/ + dockerfile: Dockerfile + image: ghcr.io/burnt-labs/xion/zk-email-backend:latest + environment: + - XION_RPC_URL=http://haproxy:26657 + - XION_API_URL=http://haproxy:1317 + - CHAIN_ID=xion-devnet-1 + ports: + - "4500" + volumes: + - ./zk-email-backend/config.json:/usr/src/app/config.json:ro + depends_on: + xion: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:4500/health || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + networks: + - devnet + + zk-email-prover: + profiles: ["zk", "full"] + build: + context: zk-email-prover/ + dockerfile: Dockerfile.rapidsnark + image: ghcr.io/burnt-labs/xion/zk-email-prover:latest + environment: + - BACKEND_URL=http://zk-email-backend:4500 ports: - - "3004" + - "8081" + depends_on: + - zk-email-backend + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:8081/health || exit 1"] + interval: 15s + timeout: 10s + retries: 5 + networks: + - devnet + + zk-email-worker: + profiles: ["zk", "full"] + build: + context: zk-email-worker/ + dockerfile: Dockerfile + image: ghcr.io/burnt-labs/xion/zk-email-worker:latest + environment: + - PROVER_URL=http://zk-email-prover:8081 + - BACKEND_URL=http://zk-email-backend:4500 + - XION_RPC_URL=http://haproxy:26657 + - CHAIN_ID=xion-devnet-1 + ports: + - "8082" + depends_on: + - zk-email-prover + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:8082/ || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + networks: + - devnet + + # ═══════════════════════════════════════════════════════════════════════════ + # IBC PROFILE + # ═══════════════════════════════════════════════════════════════════════════ + + osmosis: + image: ghcr.io/strangelove-ventures/heighliner/osmosis:v28.0.0 + profiles: ["ibc", "full"] + user: "1025:1025" + entrypoint: ["/bin/sh", "-c"] + command: + - | + if [ ! -f /home/heighliner/.osmosisd/config/genesis.json ]; then + osmosisd init validator --chain-id localosmo-1 --home /home/heighliner/.osmosisd + sed -i 's/timeout_commit = "5s"/timeout_commit = "1s"/' /home/heighliner/.osmosisd/config/config.toml + sed -i 's/timeout_propose = "3s"/timeout_propose = "1s"/' /home/heighliner/.osmosisd/config/config.toml + sed -i 's/laddr = "tcp:\/\/127.0.0.1:26657"/laddr = "tcp:\/\/0.0.0.0:26657"/' /home/heighliner/.osmosisd/config/config.toml + sed -i 's/enable = false/enable = true/' /home/heighliner/.osmosisd/config/app.toml + sed -i 's/cors_allowed_origins = \[\]/cors_allowed_origins = ["*"]/' /home/heighliner/.osmosisd/config/config.toml + osmosisd keys add validator --keyring-backend test --home /home/heighliner/.osmosisd + VALADDR=$$(osmosisd keys show validator -a --keyring-backend test --home /home/heighliner/.osmosisd) + osmosisd genesis add-genesis-account $$VALADDR 1000000000000uosmo --home /home/heighliner/.osmosisd + echo "${RELAYER_MNEMONIC}" | osmosisd keys add relayer --recover --keyring-backend test --home /home/heighliner/.osmosisd + RELAYADDR=$$(osmosisd keys show relayer -a --keyring-backend test --home /home/heighliner/.osmosisd) + osmosisd genesis add-genesis-account $$RELAYADDR 10000000000uosmo --home /home/heighliner/.osmosisd + osmosisd genesis gentx validator 500000000000uosmo --chain-id localosmo-1 --keyring-backend test --home /home/heighliner/.osmosisd + osmosisd genesis collect-gentxs --home /home/heighliner/.osmosisd + fi + osmosisd start --home /home/heighliner/.osmosisd + volumes: + - osmosis-data:/home/heighliner/.osmosisd + healthcheck: + test: ["CMD-SHELL", "osmosisd status --home /home/heighliner/.osmosisd 2>&1 | grep -q 'latest_block_height'"] + interval: 10s + timeout: 5s + retries: 30 + networks: + - devnet + + noble: + image: ghcr.io/noble-assets/noble:v11.3.0 + profiles: ["ibc", "full"] + user: "1025:1025" + entrypoint: ["/bin/sh", "-c"] + command: + - | + if [ ! -f /home/heighliner/.noble/config/genesis.json ]; then + nobled init validator --chain-id noble-devnet-1 --home /home/heighliner/.noble + sed -i 's/timeout_commit = "5s"/timeout_commit = "1s"/' /home/heighliner/.noble/config/config.toml + sed -i 's/timeout_propose = "3s"/timeout_propose = "1s"/' /home/heighliner/.noble/config/config.toml + sed -i 's/laddr = "tcp:\/\/127.0.0.1:26657"/laddr = "tcp:\/\/0.0.0.0:26657"/' /home/heighliner/.noble/config/config.toml + sed -i 's/enable = false/enable = true/' /home/heighliner/.noble/config/app.toml + sed -i 's/cors_allowed_origins = \[\]/cors_allowed_origins = ["*"]/' /home/heighliner/.noble/config/config.toml + nobled keys add validator --keyring-backend test --home /home/heighliner/.noble + VALADDR=$$(nobled keys show validator -a --keyring-backend test --home /home/heighliner/.noble) + nobled keys add minter --keyring-backend test --home /home/heighliner/.noble + MINTER=$$(nobled keys show minter -a --keyring-backend test --home /home/heighliner/.noble) + echo "${RELAYER_MNEMONIC}" | nobled keys add relayer --recover --keyring-backend test --home /home/heighliner/.noble + RELAYADDR=$$(nobled keys show relayer -a --keyring-backend test --home /home/heighliner/.noble) + nobled genesis add-genesis-account $$VALADDR 1000000000000ustake --home /home/heighliner/.noble + nobled genesis add-genesis-account $$MINTER 1000000ustake --home /home/heighliner/.noble + nobled genesis add-genesis-account $$RELAYADDR 10000000000ustake --home /home/heighliner/.noble + nobled genesis gentx validator 500000000000ustake --chain-id noble-devnet-1 --keyring-backend test --home /home/heighliner/.noble + nobled genesis collect-gentxs --home /home/heighliner/.noble + GENESIS=/home/heighliner/.noble/config/genesis.json + TEMP=/tmp/genesis.json + jq --arg addr "$$VALADDR" '.app_state.authority.owner = $$addr' $$GENESIS > $$TEMP && mv $$TEMP $$GENESIS + jq '.app_state.staking.params.bond_denom = "ustake"' $$GENESIS > $$TEMP && mv $$TEMP $$GENESIS + jq '.app_state.bank.denom_metadata += [{"description":"Circle USD Coin","denom_units":[{"denom":"uusdc","exponent":0,"aliases":["microusdc"]},{"denom":"usdc","exponent":6}],"base":"uusdc","display":"usdc","name":"Circle USD Coin","symbol":"USDC"}]' $$GENESIS > $$TEMP && mv $$TEMP $$GENESIS + jq '.app_state."fiat-tokenfactory".mintingDenom = {"denom":"uusdc"}' $$GENESIS > $$TEMP && mv $$TEMP $$GENESIS + jq '.app_state."fiat-tokenfactory".paused.paused = false' $$GENESIS > $$TEMP && mv $$TEMP $$GENESIS + jq --arg addr "$$VALADDR" '.app_state."fiat-tokenfactory".owner = {"address":$$addr}' $$GENESIS > $$TEMP && mv $$TEMP $$GENESIS + jq --arg addr "$$VALADDR" '.app_state."fiat-tokenfactory".masterMinter = {"address":$$addr}' $$GENESIS > $$TEMP && mv $$TEMP $$GENESIS + jq --arg ctrl "$$VALADDR" --arg minter "$$MINTER" '.app_state."fiat-tokenfactory".minterControllerList = [{"controller":$$ctrl,"minter":$$minter}]' $$GENESIS > $$TEMP && mv $$TEMP $$GENESIS + jq --arg minter "$$MINTER" '.app_state."fiat-tokenfactory".mintersList = [{"address":$$minter,"allowance":{"denom":"uusdc","amount":"1000000000000000"}}]' $$GENESIS > $$TEMP && mv $$TEMP $$GENESIS + fi + nobled start --home /home/heighliner/.noble + volumes: + - noble-data:/home/heighliner/.noble + healthcheck: + test: ["CMD-SHELL", "nobled status --home /home/heighliner/.noble 2>&1 | grep -q 'latest_block_height'"] + interval: 10s + timeout: 5s + retries: 30 + networks: + - devnet + + hermes: + image: ghcr.io/informalsystems/hermes:v1.12.0 + profiles: ["ibc", "full"] + volumes: + - ./config/hermes/config.toml:/home/hermes/.hermes/config.toml:ro + - hermes-data:/home/hermes/.hermes/keys + entrypoint: ["/bin/sh", "-c"] + command: + - | + echo "Waiting for chains to be ready..." + until hermes health-check 2>/dev/null; do sleep 5; done + + echo "${RELAYER_MNEMONIC}" > /tmp/mnemonic.txt + hermes keys add --chain xion-devnet-1 --mnemonic-file /tmp/mnemonic.txt --overwrite || true + hermes keys add --chain localosmo-1 --mnemonic-file /tmp/mnemonic.txt --overwrite || true + hermes keys add --chain noble-devnet-1 --mnemonic-file /tmp/mnemonic.txt --overwrite || true + rm /tmp/mnemonic.txt + + hermes create client --host-chain xion-devnet-1 --reference-chain localosmo-1 + hermes create client --host-chain localosmo-1 --reference-chain xion-devnet-1 + hermes create client --host-chain xion-devnet-1 --reference-chain noble-devnet-1 + hermes create client --host-chain noble-devnet-1 --reference-chain xion-devnet-1 + + hermes create connection --a-chain xion-devnet-1 --b-chain localosmo-1 + hermes create connection --a-chain xion-devnet-1 --b-chain noble-devnet-1 + + hermes create channel --a-chain xion-devnet-1 --a-connection connection-0 --a-port transfer --b-port transfer + hermes create channel --a-chain xion-devnet-1 --a-connection connection-1 --a-port transfer --b-port transfer + + echo "IBC channels created. Starting relayer..." + hermes start depends_on: xion: condition: service_healthy + osmosis: + condition: service_healthy + noble: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "hermes health-check 2>&1 | grep -q 'healthy'"] + interval: 30s + timeout: 10s + retries: 10 networks: - - default + - devnet + +# ═════════════════════════════════════════════════════════════════════════════ +# NETWORKS & VOLUMES +# ═════════════════════════════════════════════════════════════════════════════ networks: - default: + devnet: volumes: shared: - indexer-db: + postgres-data: + oauth3-data: + osmosis-data: + noble-data: + hermes-data: diff --git a/oauth2-api-service/.gitkeep b/oauth2-api-service/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/oauth2-clients-dashboard/.gitkeep b/oauth2-clients-dashboard/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/oauth3/.gitkeep b/oauth3/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/xion-indexer-proxy/.gitkeep b/xion-indexer-proxy/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/zk-email-backend/.gitkeep b/zk-email-backend/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/zk-email-prover/.gitkeep b/zk-email-prover/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/zk-email-worker/.gitkeep b/zk-email-worker/.gitkeep new file mode 100644 index 0000000..e69de29 From ebe76c27980e36b05a0617a7799f23469c074d40 Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:26:05 +0000 Subject: [PATCH 06/16] feat: add post-genesis contract deployment script (DO-247) Adds scripts/init/deploy-contracts.sh that runs after the chain starts producing blocks to: - Instantiate abstract account contract (code_id=1) - Instantiate treasury/fee-granter contract (code_id=2) - Fund the treasury for gasless UX - Output contract addresses for downstream services Also adds deploy-contracts service to docker-compose.yml that runs as a one-shot init container in the apps/oauth/zk/full profiles. --- docker-compose.yml | 20 +++ scripts/init/deploy-contracts.sh | 229 +++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+) create mode 100755 scripts/init/deploy-contracts.sh diff --git a/docker-compose.yml b/docker-compose.yml index 3fff5dd..4e6c04b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -102,6 +102,26 @@ services: networks: - devnet + deploy-contracts: + image: ghcr.io/burnt-labs/xion/xion:${XIOND_VERSION:-latest} + profiles: ["apps", "oauth", "zk", "full"] + entrypoint: /home/${DAEMON_NAME}/init/deploy-contracts.sh + env_file: + - .env + environment: + - XION_RPC=http://xion:26657 + - OUTPUT_FILE=/home/${DAEMON_NAME}/.shared/deploy-contracts.env + depends_on: + xion: + condition: service_healthy + working_dir: /home/${DAEMON_NAME} + volumes: + - shared:/home/${DAEMON_NAME}/.shared + - ./scripts/init:/home/${DAEMON_NAME}/init + networks: + - devnet + restart: "no" + xion-explorer: profiles: ["core", "apps", "oauth", "zk", "ibc", "full"] build: diff --git a/scripts/init/deploy-contracts.sh b/scripts/init/deploy-contracts.sh new file mode 100755 index 0000000..b4b56d8 --- /dev/null +++ b/scripts/init/deploy-contracts.sh @@ -0,0 +1,229 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ═══════════════════════════════════════════════════════════════════════════ +# deploy-contracts.sh — Post-genesis contract deployment for devnet +# +# Instantiates abstract account + treasury (fee granter) contracts after +# the chain starts producing blocks. The entrypoint.sh stores WASM codes +# in genesis (code_id 1 = abstract account, code_id 2 = treasury) but +# does NOT instantiate them. This script does the instantiation step. +# +# Usage: Run as a one-shot init container after xion is healthy. +# docker compose run --rm deploy-contracts +# ═══════════════════════════════════════════════════════════════════════════ + +SCRIPTS_DIR=$(dirname "$0") + +# Load environment +if [ -f "${HOME}/.env" ]; then + source "${HOME}/.env" +fi + +# Defaults +CHAIN_ID="${CHAIN_ID:-xion-devnet-1}" +DAEMON_NAME="${DAEMON_NAME:-xiond}" +DEFAULT_DENOM="${DEFAULT_DENOM:-uxion}" +NODE="${XION_RPC:-http://xion:26657}" +ABSTRAXION_KEY="abstraxion" + +# The mnemonic is the same devnet mnemonic used in entrypoint.sh +MNEMONIC="${MNEMONIC:?MNEMONIC is required}" + +OUTPUT_FILE="${OUTPUT_FILE:-/home/${DAEMON_NAME}/deploy-contracts.env}" + +# ─── Helpers ────────────────────────────────────────────────────────────── + +log() { echo "[deploy-contracts] $*"; } + +wait_for_chain() { + log "Waiting for chain to produce blocks..." + local attempts=0 + while ! ${DAEMON_NAME} status --node "${NODE}" 2>/dev/null | jq -e '.sync_info.latest_block_height | tonumber > 1' > /dev/null 2>&1; do + attempts=$((attempts + 1)) + if [ $attempts -ge 120 ]; then + log "ERROR: Chain not ready after 120s" + exit 1 + fi + sleep 1 + done + log "Chain is producing blocks" +} + +recover_key() { + log "Recovering deployer key '${ABSTRAXION_KEY}'..." + echo "${MNEMONIC}" | ${DAEMON_NAME} keys add "${ABSTRAXION_KEY}" \ + --account 1 --index 0 \ + --keyring-backend test --recover --output json 2>/dev/null || true + DEPLOYER_ADDR=$(${DAEMON_NAME} keys show "${ABSTRAXION_KEY}" -a --keyring-backend test) + log "Deployer address: ${DEPLOYER_ADDR}" +} + +tx_flags() { + echo "--from ${ABSTRAXION_KEY} --keyring-backend test --chain-id ${CHAIN_ID} --node ${NODE} --gas auto --gas-adjustment 1.5 --gas-prices 0.001${DEFAULT_DENOM} -y --output json" +} + +wait_for_tx() { + local txhash="$1" + local attempts=0 + while ! ${DAEMON_NAME} query tx "${txhash}" --node "${NODE}" --output json 2>/dev/null | jq -e '.code == 0' > /dev/null 2>&1; do + attempts=$((attempts + 1)) + if [ $attempts -ge 30 ]; then + log "ERROR: tx ${txhash} not confirmed after 30s" + ${DAEMON_NAME} query tx "${txhash}" --node "${NODE}" --output json 2>/dev/null || true + exit 1 + fi + sleep 1 + done +} + +# ─── Contract Instantiation ────────────────────────────────────────────── + +instantiate_abstract_account() { + local code_id=1 + log "Instantiating abstract account contract (code_id=${code_id})..." + + local init_msg='{"account_owner":{"key":"Ag=="}}' + + local result + result=$(${DAEMON_NAME} tx wasm instantiate "${code_id}" "${init_msg}" \ + --label "abstract-account-devnet" \ + --admin "${DEPLOYER_ADDR}" \ + $(tx_flags) 2>&1) + + local txhash + txhash=$(echo "${result}" | jq -r '.txhash // empty') + if [ -z "${txhash}" ]; then + log "WARN: Abstract account instantiation may have failed: ${result}" + AA_CONTRACT_ADDR="" + return + fi + + wait_for_tx "${txhash}" + AA_CONTRACT_ADDR=$(${DAEMON_NAME} query tx "${txhash}" --node "${NODE}" --output json | \ + jq -r '.events[] | select(.type=="instantiate") | .attributes[] | select(.key=="_contract_address") | .value') + log "Abstract account contract: ${AA_CONTRACT_ADDR}" +} + +instantiate_treasury() { + local code_id=2 + log "Instantiating treasury/fee-granter contract (code_id=${code_id})..." + + # Treasury instantiate msg based on e2e test patterns + # This sets up a basic fee granter with common authz grants + local init_msg + init_msg=$(cat <<'EOF' +{ + "admin": null, + "type_urls": [ + "/cosmos.bank.v1beta1.MsgSend", + "/cosmwasm.wasm.v1.MsgExecuteContract" + ], + "grant_configs": [ + { + "description": "Bank send authorization", + "authorization": { + "type_url": "/cosmos.authz.v1beta1.GenericAuthorization", + "value": "CiEvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5k" + }, + "optional": true + }, + { + "description": "Wasm execute authorization", + "authorization": { + "type_url": "/cosmos.authz.v1beta1.GenericAuthorization", + "value": "CicvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3Q=" + }, + "optional": true + } + ], + "fee_config": { + "description": "Devnet fee allowance", + "allowance": { + "type_url": "/cosmos.feegrant.v1beta1.BasicAllowance", + "value": "" + }, + "expiration": 31536000 + }, + "params": { + "redirect_url": "http://localhost:4173", + "icon_url": "https://xion.burnt.com/icon.png", + "metadata": "{}" + } +} +EOF + ) + + local result + result=$(${DAEMON_NAME} tx wasm instantiate "${code_id}" "${init_msg}" \ + --label "treasury-fee-granter-devnet" \ + --admin "${DEPLOYER_ADDR}" \ + $(tx_flags) 2>&1) + + local txhash + txhash=$(echo "${result}" | jq -r '.txhash // empty') + if [ -z "${txhash}" ]; then + log "WARN: Treasury instantiation may have failed: ${result}" + TREASURY_ADDR="" + return + fi + + wait_for_tx "${txhash}" + TREASURY_ADDR=$(${DAEMON_NAME} query tx "${txhash}" --node "${NODE}" --output json | \ + jq -r '.events[] | select(.type=="instantiate") | .attributes[] | select(.key=="_contract_address") | .value') + log "Treasury/fee-granter contract: ${TREASURY_ADDR}" +} + +fund_treasury() { + if [ -z "${TREASURY_ADDR}" ]; then + log "WARN: No treasury address, skipping funding" + return + fi + + local fund_amount="10000000000${DEFAULT_DENOM}" # 10,000 XION + log "Funding treasury with ${fund_amount}..." + + local result + result=$(${DAEMON_NAME} tx bank send "${DEPLOYER_ADDR}" "${TREASURY_ADDR}" "${fund_amount}" \ + $(tx_flags) 2>&1) + + local txhash + txhash=$(echo "${result}" | jq -r '.txhash // empty') + if [ -n "${txhash}" ]; then + wait_for_tx "${txhash}" + log "Treasury funded" + else + log "WARN: Treasury funding may have failed: ${result}" + fi +} + +write_output() { + log "Writing deployment output to ${OUTPUT_FILE}..." + cat > "${OUTPUT_FILE}" < Date: Thu, 5 Mar 2026 21:26:05 +0000 Subject: [PATCH 07/16] fix: enable abstractaccount allowed_code_ids and configure Stytch JWK audience - Uncomment abstractaccount.params.allowed_code_ids = ["1"] (required for AA) - Add allow_all_code_ids = false per e2e test reference - Configure JWK audience for Stytch test project - Fetch and embed Stytch JWKS public key for JWT validation - Update entrypoint.sh to pass Stytch/abstraxion args to jq - Fix jq syntax (missing pipe operator before abstractaccount line) --- .env | 11 +++++++---- scripts/init/entrypoint.sh | 8 +++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.env b/.env index fc2bae7..e71526f 100644 --- a/.env +++ b/.env @@ -22,14 +22,17 @@ SOURCE_CHAIN_API="https://api.xion-testnet-2.burnt.com:443" # first should be account, second should be treasury, more can be appended code ids are assigned sequentially starting from 1 SOURCE_CHAIN_CODE_IDS="1 1260" +STYTCH_AUD="project-test-1aa439cd-842b-4d3b-b2a6-37899cf83ca9" +STYTCH_JWK='{"alg":"RS256","e":"AQAB","kid":"jwk-test-a93974ec-5fb7-4970-957d-7d3439077841","kty":"RSA","n":"80EHR58Nopm1CeGWBTx_yGO3REn9mCfktSyb00Rf2x12WIiZhkVKcsXIA6GyUJJfrRomKWWPbPeTz1NMx3Oz6VY8nWpZIhZ93QEFqXmjLMJeuf1UNLTzyI9UM32GYu9EEne7LW39i7-ke0Hd9q0Ru-eBA86qNQ7M3sz_VhYZFQCSKZPUFtTXLEzZVAcvCP0yZEIXyxvSjxAIgY7p0mvF7WPsPSkqBXzwgnPd5P1A8hldCH2qeCwqmoZLmPLniRRTlSUO1Nog7YyxTCPp1bRskSAxkawqeB3hzRZPnDEHM9HrE3eamiKAGpBfkkfmkGT0MpA8J5de-BH2bLk_SxZERQ","use":"sig"}' + MODIFY_GENESIS_JQ=' - # .genesis_time = "2025-01-28T16:00:00Z" | .app_state.gov.params.expedited_voting_period = "0h1m0s" | .app_state.feeabs.epochs = [] | .app_state.feeabs.params.native_ibced_in_osmosis = "" | - .app_state.feeabs.params.chain_name = "" - # .app_state.abstractaccount.params.allowed_code_ids = ["1"] - # .app_state.jwk.audienceList = [{"aud": env.JWK_AUD, "key": env.JWK_KEY, "admin": env.JWK_ADMIN}] + .app_state.feeabs.params.chain_name = "" | + .app_state.abstractaccount.params.allowed_code_ids = ["1"] | + .app_state.abstractaccount.params.allow_all_code_ids = false | + .app_state.jwk.audienceList = [{"aud": $stytch_aud, "key": $stytch_jwk, "admin": $abstraxion_addr}] ' diff --git a/scripts/init/entrypoint.sh b/scripts/init/entrypoint.sh index 2b04ba5..b83c2be 100755 --- a/scripts/init/entrypoint.sh +++ b/scripts/init/entrypoint.sh @@ -232,7 +232,13 @@ initialize_genesis() { if [[ -n "${MODIFY_GENESIS_JQ}" ]]; then echo "Modifying genesis.json..." - modify_genesis_jq "" "${MODIFY_GENESIS_JQ}" "{}" + jq --arg module "" --argjson params '{}' \ + --arg stytch_aud "${STYTCH_AUD:-}" \ + --arg stytch_jwk "${STYTCH_JWK:-}" \ + --arg abstraxion_addr "${ABSTRAXION_ADDRESS:-}" \ + "${MODIFY_GENESIS_JQ}" "${DAEMON_HOME}/config/genesis.json" > "${TMP_DIR}/genesis.json" + diff -u "${DAEMON_HOME}/config/genesis.json" "${TMP_DIR}/genesis.json" || true + mv "${TMP_DIR}/genesis.json" "${DAEMON_HOME}/config/genesis.json" fi echo "Collecting gentxs..." From 8186f2174b8929e4c9c497d066ed1ecce91ab558 Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:26:05 +0000 Subject: [PATCH 08/16] chore: update subql-node-cosmos to v4.0.1 --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4e6c04b..e785cd6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -207,7 +207,7 @@ services: - devnet xion-indexer-node: - image: subquerynetwork/subql-node-cosmos:v3.11.2 + image: subquerynetwork/subql-node-cosmos:v4.0.1 profiles: ["apps", "oauth", "zk", "full"] depends_on: postgresql: From 64c902069ff20789b96c8efe0abc75b75b28cd86 Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:26:05 +0000 Subject: [PATCH 09/16] chore: wire Stytch credentials into devnet env and compose --- .env.example | 5 ++++- docker-compose.yml | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index b87ba33..4d2ab24 100644 --- a/.env.example +++ b/.env.example @@ -44,10 +44,13 @@ POSTGRES_DB=postgres SUB_COMMAND=forceClean # --- Dashboard --- -STYTCH_PUBLIC_TOKEN=public-token-test-placeholder +STYTCH_PUBLIC_TOKEN=public-token-test-823bab5f-5fe6-4a3f-b49a-ca59763be42a NUMIA_TOKEN=placeholder FEE_GRANTER_ADDRESS= ZKEMAIL_FLAG=false # --- IBC Relayer --- RELAYER_MNEMONIC="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art" + +STYTCH_PROJECT_ID=project-test-1aa439cd-842b-4d3b-b2a6-37899cf83ca9 +STYTCH_SECRET=PLACEHOLDER_NEED_SECRET diff --git a/docker-compose.yml b/docker-compose.yml index e785cd6..c9cc15a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -172,6 +172,8 @@ services: - XION_API_URL=http://haproxy:1317 - XION_GRPC_URL=haproxy:9090 - CHAIN_ID=xion-devnet-1 + - STYTCH_PROJECT_ID=${STYTCH_PROJECT_ID:-project-test-1aa439cd-842b-4d3b-b2a6-37899cf83ca9} + - STYTCH_SECRET=${STYTCH_SECRET:-PLACEHOLDER_NEED_SECRET} ports: - "3001" depends_on: @@ -303,7 +305,7 @@ services: - VITE_XION_API_URL=http://haproxy:1317 - VITE_XION_RPC_URL=http://haproxy:26657 - VITE_ABSTRAXION_API_URL=http://account-abstraction-api:3001 - - VITE_STYTCH_PUBLIC_TOKEN=${STYTCH_PUBLIC_TOKEN:-public-token-test-placeholder} + - VITE_STYTCH_PUBLIC_TOKEN=${STYTCH_PUBLIC_TOKEN:-public-token-test-823bab5f-5fe6-4a3f-b49a-ca59763be42a} - VITE_NUMIA_TOKEN=${NUMIA_TOKEN:-placeholder} - VITE_DEFAULT_INDEXER_URL=http://xion-indexer-graphql:3000 - VITE_FEE_GRANTER_ADDRESS=${FEE_GRANTER_ADDRESS:-} From 42ad24fdd5758ce7fc530fe959b45570e0721a24 Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:26:05 +0000 Subject: [PATCH 10/16] fix: P2P port 26656, add assets port 3004, sync .env.example with .env --- .env.example | 9 ++++++++- README.md | 7 ++++--- config/haproxy.cfg | 6 +++--- docker-compose.yml | 3 ++- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/.env.example b/.env.example index 4d2ab24..69b952a 100644 --- a/.env.example +++ b/.env.example @@ -27,12 +27,19 @@ SOURCE_CHAIN_CODE_IDS="1 1260" FAUCET_ACCOUNTS="10" FAUCET_AMOUNT="100000000" +# --- Stytch / JWK (used in genesis modifications) --- +STYTCH_AUD="project-test-1aa439cd-842b-4d3b-b2a6-37899cf83ca9" +STYTCH_JWK='{"alg":"RS256","e":"AQAB","kid":"jwk-test-a93974ec-5fb7-4970-957d-7d3439077841","kty":"RSA","n":"80EHR58Nopm1CeGWBTx_yGO3REn9mCfktSyb00Rf2x12WIiZhkVKcsXIA6GyUJJfrRomKWWPbPeTz1NMx3Oz6VY8nWpZIhZ93QEFqXmjLMJeuf1UNLTzyI9UM32GYu9EEne7LW39i7-ke0Hd9q0Ru-eBA86qNQ7M3sz_VhYZFQCSKZPUFtTXLEzZVAcvCP0yZEIXyxvSjxAIgY7p0mvF7WPsPSkqBXzwgnPd5P1A8hldCH2qeCwqmoZLmPLniRRTlSUO1Nog7YyxTCPp1bRskSAxkawqeB3hzRZPnDEHM9HrE3eamiKAGpBfkkfmkGT0MpA8J5de-BH2bLk_SxZERQ","use":"sig"}' + # --- Genesis Modifications --- MODIFY_GENESIS_JQ=' .app_state.gov.params.expedited_voting_period = "0h1m0s" | .app_state.feeabs.epochs = [] | .app_state.feeabs.params.native_ibced_in_osmosis = "" | - .app_state.feeabs.params.chain_name = "" + .app_state.feeabs.params.chain_name = "" | + .app_state.abstractaccount.params.allowed_code_ids = ["1"] | + .app_state.abstractaccount.params.allow_all_code_ids = false | + .app_state.jwk.audienceList = [{"aud": $stytch_aud, "key": $stytch_jwk, "admin": $abstraxion_addr}] ' # --- Postgres --- diff --git a/README.md b/README.md index eb9dcaf..df4c28c 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,10 @@ make full # everything | 3001 | AA API | 8081 | ZK Email Prover | | 3002 | Indexer GraphQL | 8082 | ZK Email Worker | | 3003 | Developer Portal | 8788 | Staking | -| 4173 | Dashboard | 26757 | Osmosis RPC | -| 5173 | Explorer | 26857 | Noble RPC | -| 8444 | HAProxy Stats | 9190/9290 | Osmosis/Noble gRPC | +| 3004 | Assets | 26757 | Osmosis RPC | +| 4173 | Dashboard | 26857 | Noble RPC | +| 5173 | Explorer | 9190/9290 | Osmosis/Noble gRPC | +| 8444 | HAProxy Stats | 26656 | Xion P2P | ## Commands diff --git a/config/haproxy.cfg b/config/haproxy.cfg index 99e8b15..75c5242 100644 --- a/config/haproxy.cfg +++ b/config/haproxy.cfg @@ -51,10 +51,10 @@ listen rpc http-response set-header Access-Control-Allow-Headers "Content-Type" server-template s 10 xion:26657 check init-addr last,none resolvers default -listen client - bind *:26658 +listen p2p + bind *:26656 mode tcp - server-template s 10 xion:26658 check init-addr last,none resolvers default + server-template s 10 xion:26656 check init-addr last,none resolvers default # ═══════════════════════════════════════════════════════════════════════════ # CORE — Faucet & Explorer diff --git a/docker-compose.yml b/docker-compose.yml index c9cc15a..2768648 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,11 +30,12 @@ services: - "1317:1317" # Xion REST/LCD - "9090:9090" # Xion gRPC - "26657:26657" # Xion RPC - - "26658:26658" # Xion P2P + - "26656:26656" # Xion P2P - "3000:3000" # Faucet - "3001:3001" # AA API - "3002:3002" # Indexer GraphQL - "3003:3003" # Developer Portal + - "3004:3004" # Assets - "4173:4173" # Dashboard - "5173:5173" # Explorer - "8001:8001" # Indexer Proxy From 2ed4410fbe140001e91558bb3d1193d12d36f5bf Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:26:05 +0000 Subject: [PATCH 11/16] chore: remove oauth3 from devnet stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not needed — use Stytch directly for OAuth2 flows. --- .gitmodules | 4 ---- docker-compose.yml | 33 +++------------------------------ oauth3/.gitkeep | 0 3 files changed, 3 insertions(+), 34 deletions(-) delete mode 100644 oauth3/.gitkeep diff --git a/.gitmodules b/.gitmodules index d8645ca..691e905 100644 --- a/.gitmodules +++ b/.gitmodules @@ -38,10 +38,6 @@ path = account-abstraction-api url = https://github.com/burnt-labs/account-abstraction-api.git branch = chore/devnet -[submodule "oauth3"] - path = oauth3 - url = https://github.com/burnt-labs/oauth3.git - branch = chore/devnet [submodule "oauth2-api-service"] path = oauth2-api-service url = https://github.com/burnt-labs/oauth2-api-service.git diff --git a/docker-compose.yml b/docker-compose.yml index 2768648..8de8391 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ # Profiles: # core — xion (3 validators) + haproxy + explorer + faucet # apps — core + AA API + dashboard + staking + dev-portal + indexer + assets -# oauth — apps + oauth3 + oauth2-api-service + oauth2-clients-dashboard +# oauth — apps + oauth2-api-service + oauth2-clients-dashboard # zk — apps + zk-email-backend + zk-email-prover + zk-email-worker # ibc — core + osmosis + noble + hermes relayer # full — everything @@ -402,32 +402,6 @@ services: # OAUTH PROFILE # ═══════════════════════════════════════════════════════════════════════════ - oauth3: - profiles: ["oauth", "full"] - build: - context: oauth3/ - dockerfile: Dockerfile - image: ghcr.io/burnt-labs/xion/oauth3:latest - environment: - - DATABASE_URL=sqlite:///app/data/oauth3.db - - RUST_LOG=info,oauth3=debug - - XION_RPC_URL=http://haproxy:26657 - - XION_API_URL=http://haproxy:1317 - - CHAIN_ID=xion-devnet-1 - ports: - - "8080" - volumes: - - oauth3-data:/app/data - depends_on: - xion: - condition: service_healthy - healthcheck: - test: ["CMD-SHELL", "wget -qO- http://localhost:8080/health || exit 1"] - interval: 15s - timeout: 5s - retries: 5 - networks: - - devnet oauth2-api-service: profiles: ["oauth", "full"] @@ -436,13 +410,13 @@ services: dockerfile: Dockerfile image: ghcr.io/burnt-labs/xion/oauth2-api-service:latest environment: - - OAUTH3_URL=http://oauth3:8080 - XION_RPC_URL=http://haproxy:26657 - CHAIN_ID=xion-devnet-1 ports: - "8002" depends_on: - - oauth3 + xion: + condition: service_healthy healthcheck: test: ["CMD-SHELL", "wget -qO- http://localhost:8002/ || exit 1"] interval: 15s @@ -686,7 +660,6 @@ networks: volumes: shared: postgres-data: - oauth3-data: osmosis-data: noble-data: hermes-data: diff --git a/oauth3/.gitkeep b/oauth3/.gitkeep deleted file mode 100644 index e69de29..0000000 From 65015985bbf2ee980149a36aedab4725a8eb7822 Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:26:05 +0000 Subject: [PATCH 12/16] chore: remove xion-indexer and xion-indexer-proxy from devnet stack Not needed per TwiceBurnt. --- .gitmodules | 8 ---- docker-compose.yml | 83 ------------------------------------- xion-indexer | 1 - xion-indexer-proxy/.gitkeep | 0 4 files changed, 92 deletions(-) delete mode 160000 xion-indexer delete mode 100644 xion-indexer-proxy/.gitkeep diff --git a/.gitmodules b/.gitmodules index 691e905..797a49d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,14 +26,6 @@ path = xion-assets url = https://github.com/burnt-labs/xion-assets.git branch = chore/devnet -[submodule "xion-indexer"] - path = xion-indexer - url = https://github.com/burnt-labs/xion-indexer.git - branch = chore/devnet -[submodule "xion-indexer-proxy"] - path = xion-indexer-proxy - url = https://github.com/burnt-labs/xion-indexer-proxy.git - branch = chore/devnet [submodule "account-abstraction-api"] path = account-abstraction-api url = https://github.com/burnt-labs/account-abstraction-api.git diff --git a/docker-compose.yml b/docker-compose.yml index 8de8391..33503e6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -209,88 +209,6 @@ services: networks: - devnet - xion-indexer-node: - image: subquerynetwork/subql-node-cosmos:v4.0.1 - profiles: ["apps", "oauth", "zk", "full"] - depends_on: - postgresql: - condition: service_healthy - xion: - condition: service_healthy - restart: always - environment: - DB_USER: ${POSTGRES_USER:-postgres} - DB_PASS: ${POSTGRES_PASSWORD:-postgres} - DB_DATABASE: ${POSTGRES_DB:-postgres} - DB_HOST: postgresql - DB_PORT: 5432 - volumes: - - ./xion-indexer:/app - command: - - ${SUB_COMMAND:-forceClean} - - -f=/app - - --db-schema=app - - --unsafe - healthcheck: - test: ["CMD-SHELL", "curl -sf http://localhost:3000/ready || exit 1"] - interval: 10s - timeout: 5s - retries: 15 - networks: - - devnet - - xion-indexer-graphql: - image: subquerynetwork/subql-query:latest - profiles: ["apps", "oauth", "zk", "full"] - depends_on: - postgresql: - condition: service_healthy - xion-indexer-node: - condition: service_healthy - restart: always - environment: - DB_USER: ${POSTGRES_USER:-postgres} - DB_PASS: ${POSTGRES_PASSWORD:-postgres} - DB_DATABASE: ${POSTGRES_DB:-postgres} - DB_HOST: postgresql - DB_PORT: 5432 - command: - - --name=app - - --playground - - --indexer=http://xion-indexer-node:3000 - ports: - - "3000" - healthcheck: - test: ["CMD-SHELL", "curl -sf http://localhost:3000/ || exit 1"] - interval: 10s - timeout: 5s - retries: 10 - networks: - - devnet - - xion-indexer-proxy: - profiles: ["apps", "oauth", "zk", "full"] - build: - context: xion-indexer-proxy/ - dockerfile: Dockerfile - image: ghcr.io/burnt-labs/xion/xion-indexer-proxy:latest - environment: - - UPSTREAM_HOST=http://haproxy:1317 - - CHAIN_ID=xion-devnet-1 - - INDEXER_GRAPHQL_URL=http://xion-indexer-graphql:3000 - ports: - - "8001" - depends_on: - xion-indexer-graphql: - condition: service_healthy - healthcheck: - test: ["CMD-SHELL", "wget -qO- http://localhost:8001/ || exit 1"] - interval: 15s - timeout: 5s - retries: 5 - networks: - - devnet - # --- Dashboard (Primary App) --- xion-dashboard-app: @@ -308,7 +226,6 @@ services: - VITE_ABSTRAXION_API_URL=http://account-abstraction-api:3001 - VITE_STYTCH_PUBLIC_TOKEN=${STYTCH_PUBLIC_TOKEN:-public-token-test-823bab5f-5fe6-4a3f-b49a-ca59763be42a} - VITE_NUMIA_TOKEN=${NUMIA_TOKEN:-placeholder} - - VITE_DEFAULT_INDEXER_URL=http://xion-indexer-graphql:3000 - VITE_FEE_GRANTER_ADDRESS=${FEE_GRANTER_ADDRESS:-} - VITE_DEFAULT_ACCOUNT_CONTRACT_CODE_ID=1 - VITE_ZKEMAIL_FLAG=${ZKEMAIL_FLAG:-false} diff --git a/xion-indexer b/xion-indexer deleted file mode 160000 index 4143bad..0000000 --- a/xion-indexer +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4143bad0bf036c938633507e85c761275171a850 diff --git a/xion-indexer-proxy/.gitkeep b/xion-indexer-proxy/.gitkeep deleted file mode 100644 index e69de29..0000000 From 567256d8295b2c2ea7917e842fe79194742b8ee9 Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 5 Mar 2026 21:26:05 +0000 Subject: [PATCH 13/16] chore: restore xion-indexer-proxy to devnet stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only xion-indexer was removed — xion-indexer-proxy is a separate service. --- .gitmodules | 4 ++++ docker-compose.yml | 24 ++++++++++++++++++++++++ xion-indexer-proxy/.gitkeep | 0 3 files changed, 28 insertions(+) create mode 100644 xion-indexer-proxy/.gitkeep diff --git a/.gitmodules b/.gitmodules index 797a49d..d795a82 100644 --- a/.gitmodules +++ b/.gitmodules @@ -50,3 +50,7 @@ path = zk-email-worker url = https://github.com/burnt-labs/zk-email-worker.git branch = chore/devnet +[submodule "xion-indexer-proxy"] + path = xion-indexer-proxy + url = https://github.com/burnt-labs/xion-indexer-proxy.git + branch = chore/devnet diff --git a/docker-compose.yml b/docker-compose.yml index 33503e6..06e0b9e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -316,6 +316,30 @@ services: - devnet # ═══════════════════════════════════════════════════════════════════════════ + + xion-indexer-proxy: + profiles: ["apps", "oauth", "zk", "full"] + build: + context: xion-indexer-proxy/ + dockerfile: Dockerfile + image: ghcr.io/burnt-labs/xion/xion-indexer-proxy:latest + environment: + - XION_RPC_URL=http://haproxy:26657 + - XION_API_URL=http://haproxy:1317 + - CHAIN_ID=xion-devnet-1 + ports: + - "8001:8000" + depends_on: + xion: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "wget -qO- http://localhost:8000/ || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + networks: + - devnet + # OAUTH PROFILE # ═══════════════════════════════════════════════════════════════════════════ diff --git a/xion-indexer-proxy/.gitkeep b/xion-indexer-proxy/.gitkeep new file mode 100644 index 0000000..e69de29 From d1aa87d87da46f253d1caaef7b8a4dc0d0148ac6 Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 19 Mar 2026 23:32:28 -0500 Subject: [PATCH 14/16] chore: register 6 placeholder submodules and fix xion-assets/dev-portal refs (DO-273) Register xion-indexer-proxy, oauth2-api-service, oauth2-clients-dashboard, zk-email-backend, zk-email-prover, zk-email-worker as proper submodules (replacing .gitkeep placeholders). Update xion-assets .gitmodules branch to main (chore/devnet doesn't exist upstream). Update xion-developer-portal to chore/devnet HEAD. --- .gitmodules | 2 +- oauth2-api-service | 1 + oauth2-api-service/.gitkeep | 0 oauth2-clients-dashboard | 1 + oauth2-clients-dashboard/.gitkeep | 0 xion-assets | 2 +- xion-developer-portal | 2 +- xion-indexer-proxy | 1 + xion-indexer-proxy/.gitkeep | 0 zk-email-backend | 1 + zk-email-backend/.gitkeep | 0 zk-email-prover | 1 + zk-email-prover/.gitkeep | 0 zk-email-worker | 1 + zk-email-worker/.gitkeep | 0 15 files changed, 9 insertions(+), 3 deletions(-) create mode 160000 oauth2-api-service delete mode 100644 oauth2-api-service/.gitkeep create mode 160000 oauth2-clients-dashboard delete mode 100644 oauth2-clients-dashboard/.gitkeep create mode 160000 xion-indexer-proxy delete mode 100644 xion-indexer-proxy/.gitkeep create mode 160000 zk-email-backend delete mode 100644 zk-email-backend/.gitkeep create mode 160000 zk-email-prover delete mode 100644 zk-email-prover/.gitkeep create mode 160000 zk-email-worker delete mode 100644 zk-email-worker/.gitkeep diff --git a/.gitmodules b/.gitmodules index d795a82..d921824 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,7 +25,7 @@ [submodule "xion-assets"] path = xion-assets url = https://github.com/burnt-labs/xion-assets.git - branch = chore/devnet + branch = main [submodule "account-abstraction-api"] path = account-abstraction-api url = https://github.com/burnt-labs/account-abstraction-api.git diff --git a/oauth2-api-service b/oauth2-api-service new file mode 160000 index 0000000..ea1f2bb --- /dev/null +++ b/oauth2-api-service @@ -0,0 +1 @@ +Subproject commit ea1f2bb8f9ca1fd62adcda583415284812d695ca diff --git a/oauth2-api-service/.gitkeep b/oauth2-api-service/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/oauth2-clients-dashboard b/oauth2-clients-dashboard new file mode 160000 index 0000000..a18f38a --- /dev/null +++ b/oauth2-clients-dashboard @@ -0,0 +1 @@ +Subproject commit a18f38aff1055ff8dbcae8c080ff67cde3267f8b diff --git a/oauth2-clients-dashboard/.gitkeep b/oauth2-clients-dashboard/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/xion-assets b/xion-assets index 30c5dd2..e3ffed5 160000 --- a/xion-assets +++ b/xion-assets @@ -1 +1 @@ -Subproject commit 30c5dd21f25c60c83724aa548cf8d81d110fc568 +Subproject commit e3ffed56a478394c6ffc12a179383b08bb000191 diff --git a/xion-developer-portal b/xion-developer-portal index 50c999b..2a4fed3 160000 --- a/xion-developer-portal +++ b/xion-developer-portal @@ -1 +1 @@ -Subproject commit 50c999b3e48b2a5b9e73bf502de9f01f97bd55d9 +Subproject commit 2a4fed340cbc43b8d39d39a714447ad3a76751ee diff --git a/xion-indexer-proxy b/xion-indexer-proxy new file mode 160000 index 0000000..894b549 --- /dev/null +++ b/xion-indexer-proxy @@ -0,0 +1 @@ +Subproject commit 894b549a922d54925ac4b2d466c07c6c9e3d9d3b diff --git a/xion-indexer-proxy/.gitkeep b/xion-indexer-proxy/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/zk-email-backend b/zk-email-backend new file mode 160000 index 0000000..e9f1a46 --- /dev/null +++ b/zk-email-backend @@ -0,0 +1 @@ +Subproject commit e9f1a46979f652451c434523263d7e176dddc139 diff --git a/zk-email-backend/.gitkeep b/zk-email-backend/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/zk-email-prover b/zk-email-prover new file mode 160000 index 0000000..825cb33 --- /dev/null +++ b/zk-email-prover @@ -0,0 +1 @@ +Subproject commit 825cb3376ad42e9e673e39f728c6a372e9220196 diff --git a/zk-email-prover/.gitkeep b/zk-email-prover/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/zk-email-worker b/zk-email-worker new file mode 160000 index 0000000..c8a038d --- /dev/null +++ b/zk-email-worker @@ -0,0 +1 @@ +Subproject commit c8a038df705e57c38e82143d7a737bcb00881bbd diff --git a/zk-email-worker/.gitkeep b/zk-email-worker/.gitkeep deleted file mode 100644 index e69de29..0000000 From 92261e9b32783fdc37994148ff7157b949f391d5 Mon Sep 17 00:00:00 2001 From: crucible-burnt <260729324+crucible-burnt@users.noreply.github.com> Date: Thu, 19 Mar 2026 23:32:28 -0500 Subject: [PATCH 15/16] fix(compose): align developer-portal and assets ports with Dockerfiles (DO-273) Both xion-developer-portal and xion-assets Dockerfiles expose port 3000, but compose had 3002 and 3003 respectively. Aligns ports and healthchecks. --- docker-compose.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 06e0b9e..a39f8cf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -280,12 +280,12 @@ services: - VITE_RPC_URL=http://haproxy:26657 - VITE_API_URL=http://haproxy:1317 ports: - - "3002" + - "3000" depends_on: xion: condition: service_healthy healthcheck: - test: ["CMD-SHELL", "wget -qO- http://localhost:3002/ || exit 1"] + test: ["CMD-SHELL", "wget -qO- http://localhost:3000/ || exit 1"] interval: 15s timeout: 5s retries: 5 @@ -303,12 +303,12 @@ services: environment: - VITE_CHAIN_ID=xion-devnet-1 ports: - - "3003" + - "3000" depends_on: xion: condition: service_healthy healthcheck: - test: ["CMD-SHELL", "wget -qO- http://localhost:3003/ || exit 1"] + test: ["CMD-SHELL", "wget -qO- http://localhost:3000/ || exit 1"] interval: 15s timeout: 5s retries: 5 From fb1b3eaccd22163c7af3b35e2b55b9bdfea6276e Mon Sep 17 00:00:00 2001 From: 2xburnt <169301814+2xburnt@users.noreply.github.com> Date: Wed, 1 Jul 2026 16:54:25 +0000 Subject: [PATCH 16/16] fix(compose): copy init scripts through named volume (DO-272) Avoid host bind mounts for validator init scripts by copying them through a busybox init container into a named volume. Validators and deploy-contracts mount the resulting volume read-only, which keeps local compose behavior compatible with DinD environments. Co-authored-by: Crucible --- docker-compose.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index a39f8cf..6aba1cd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,6 +20,16 @@ services: # CORE PROFILE # ═══════════════════════════════════════════════════════════════════════════ + init-scripts: + image: busybox:1.37 + profiles: ["core", "apps", "oauth", "zk", "ibc", "full"] + command: > + sh -c "cp -R /source/. /target/ && chmod +x /target/*.sh" + volumes: + - ./scripts/init:/source:ro + - init-scripts:/target + restart: "no" + haproxy: image: haproxy:3.2-alpine profiles: ["core", "apps", "oauth", "zk", "ibc", "full"] @@ -63,6 +73,9 @@ services: xion: image: ghcr.io/burnt-labs/xion/xion:${XIOND_VERSION:-latest} profiles: ["core", "apps", "oauth", "zk", "ibc", "full"] + depends_on: + init-scripts: + condition: service_completed_successfully build: context: ./xion args: @@ -99,7 +112,7 @@ services: volumes: - /home/${DAEMON_NAME} - shared:/home/${DAEMON_NAME}/.shared - - ./scripts/init:/home/${DAEMON_NAME}/init + - init-scripts:/home/${DAEMON_NAME}/init:ro networks: - devnet @@ -113,12 +126,14 @@ services: - XION_RPC=http://xion:26657 - OUTPUT_FILE=/home/${DAEMON_NAME}/.shared/deploy-contracts.env depends_on: + init-scripts: + condition: service_completed_successfully xion: condition: service_healthy working_dir: /home/${DAEMON_NAME} volumes: - shared:/home/${DAEMON_NAME}/.shared - - ./scripts/init:/home/${DAEMON_NAME}/init + - init-scripts:/home/${DAEMON_NAME}/init:ro networks: - devnet restart: "no" @@ -600,6 +615,7 @@ networks: volumes: shared: + init-scripts: postgres-data: osmosis-data: noble-data: