From 98a698af9e998fc04ec865d21dac122b1e1b7195 Mon Sep 17 00:00:00 2001 From: Bug-Hunter-X <190429156+Bug-Hunter-X@users.noreply.github.com> Date: Sat, 27 Jun 2026 13:22:18 +0100 Subject: [PATCH] Add deployment scripts and Stellar network configuration for testnet/mainnet Closes #26 by providing a repeatable deploy flow, Makefile targets, stellar.toml RPC config, and README quick-start docs so developers no longer need to reconstruct deployment steps manually. --- .gitignore | 1 + Makefile | 13 +++++ README.md | 47 ++++++++++++++++- scripts/deploy.sh | 131 ++++++++++++++++++++++++++++++++++++++++++++++ stellar.toml | 7 +++ 5 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 Makefile create mode 100755 scripts/deploy.sh create mode 100644 stellar.toml diff --git a/.gitignore b/.gitignore index b28de5e..3547bbf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /target soroban/target +.contract-ids.json **/*.rs.bk .env .DS_Store diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..25f96eb --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +.PHONY: build test deploy-testnet deploy-mainnet + +build: + cd soroban && cargo build --target wasm32-unknown-unknown --release + +test: + cd soroban && cargo test --workspace + +deploy-testnet: + NETWORK=testnet ./scripts/deploy.sh + +deploy-mainnet: + NETWORK=mainnet ./scripts/deploy.sh diff --git a/README.md b/README.md index 431f4b8..39c620f 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,49 @@ - [`contracts/`](./contracts/README.md) — reserved layout / pointers - [`soroban/`](./soroban/README.md) — Soroban design and future Rust workspace -Scaffold on-chain code with the **Stellar CLI** (`stellar contract init`) when you are ready, then publish factory and pool contract IDs to the frontend repo’s environment variables. +Contract sources live under [`soroban/`](./soroban/README.md). After deployment, publish the factory contract ID and RPC URL to the frontend repo’s environment variables. + +## Quick Start (deployment) + +### Prerequisites + +- [Rust](https://rustup.rs/) with the `wasm32-unknown-unknown` target +- [Stellar CLI](https://developers.stellar.org/docs/tools/developer-tools) (`stellar`) +- A funded Stellar identity on the target network (testnet or mainnet) + +```bash +rustup target add wasm32-unknown-unknown +stellar keys generate default --network testnet # if you do not already have an identity +``` + +Fund testnet accounts via [Friendbot](https://friendbot.stellar.org/?addr=YOUR_ADDRESS). + +Network RPC URLs and passphrases are defined in [`stellar.toml`](./stellar.toml). The deploy script registers the selected network with the CLI automatically. + +### Build, test, and deploy + +```bash +make build # compile release WASM to soroban/target/wasm32-unknown-unknown/release/ +make test # run contract unit tests + +make deploy-testnet # install pool WASM, deploy factory, initialize, write .contract-ids.json +make deploy-mainnet # same flow on mainnet (requires a funded mainnet identity) +``` + +`scripts/deploy.sh` accepts optional environment variables: + +| Variable | Default | Description | +|----------|---------|-------------| +| `NETWORK` | `testnet` | `testnet` or `mainnet` | +| `SOURCE` | `default` | Stellar CLI identity used to sign transactions | +| `ADMIN` | address of `SOURCE` | Factory admin passed to `initialize` | +| `STELLAR_TOML` | `./stellar.toml` | Network configuration file | +| `CONTRACT_IDS_FILE` | `./.contract-ids.json` | Output path for deployed IDs | + +Example with a custom identity: + +```bash +SOURCE=alice ADMIN=G... make deploy-testnet +``` + +On success, `.contract-ids.json` contains the factory contract ID and installed pool WASM hash (gitignored). diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100755 index 0000000..367b83e --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +STELLAR_TOML="${STELLAR_TOML:-$ROOT_DIR/stellar.toml}" +CONTRACT_IDS_FILE="${CONTRACT_IDS_FILE:-$ROOT_DIR/.contract-ids.json}" + +NETWORK="${NETWORK:-testnet}" +SOURCE="${SOURCE:-default}" +ADMIN="${ADMIN:-}" + +POOL_WASM="${ROOT_DIR}/soroban/target/wasm32-unknown-unknown/release/farming_pool.wasm" +FACTORY_WASM="${ROOT_DIR}/soroban/target/wasm32-unknown-unknown/release/factory.wasm" + +die() { + echo "error: $*" >&2 + exit 1 +} + +run_stellar() { + local attempt combined last_line + for attempt in 1 2 3; do + if combined="$("$@" 2>&1)"; then + last_line="$(printf '%s\n' "$combined" | awk 'NF { line = $0 } END { print line }')" + printf '%s' "$last_line" + return 0 + fi + if [[ "$combined" == *TxBadSeq* ]] && [[ "$attempt" -lt 3 ]]; then + echo "warning: transaction sequence mismatch, retrying ($attempt/3)..." >&2 + sleep 3 + continue + fi + echo "$combined" >&2 + return 1 + done +} + +require_cmd() { + command -v "$1" >/dev/null 2>&1 || die "$1 is not installed or not on PATH" +} + +toml_value() { + local section="$1" + local key="$2" + awk -v section="[$section]" -v key="$key" ' + $0 == section { in_section = 1; next } + /^\[/ { in_section = 0 } + in_section && $1 == key { + line = $0 + sub(/^[^=]*=[[:space:]]*/, "", line) + gsub(/"/, "", line) + print line + exit + } + ' "$STELLAR_TOML" +} + +require_cmd stellar + +case "$NETWORK" in + testnet | mainnet) ;; + *) + die "NETWORK must be 'testnet' or 'mainnet' (got: $NETWORK)" + ;; +esac + +[[ -f "$STELLAR_TOML" ]] || die "missing $STELLAR_TOML" + +RPC_URL="$(toml_value "$NETWORK" "rpc-url")" +NETWORK_PASSPHRASE="$(toml_value "$NETWORK" "network-passphrase")" + +[[ -n "$RPC_URL" ]] || die "rpc-url not found for [$NETWORK] in $STELLAR_TOML" +[[ -n "$NETWORK_PASSPHRASE" ]] || die "network-passphrase not found for [$NETWORK] in $STELLAR_TOML" + +stellar keys address "$SOURCE" >/dev/null 2>&1 \ + || die "Stellar identity '$SOURCE' not found. Generate one with: stellar keys generate $SOURCE" + +if [[ -z "$ADMIN" ]]; then + ADMIN="$(stellar keys address "$SOURCE")" \ + || die "ADMIN is not set and could not resolve address for SOURCE=$SOURCE" +fi + +[[ -f "$POOL_WASM" ]] || die "missing $POOL_WASM — run 'make build' first" +[[ -f "$FACTORY_WASM" ]] || die "missing $FACTORY_WASM — run 'make build' first" + +stellar network add "$NETWORK" \ + --rpc-url "$RPC_URL" \ + --network-passphrase "$NETWORK_PASSPHRASE" \ + >/dev/null 2>&1 || true + +echo "Installing farming-pool WASM..." +POOL_HASH="$( + run_stellar stellar contract install \ + --wasm "$POOL_WASM" \ + --network "$NETWORK" \ + --source "$SOURCE" \ + --quiet +)" +sleep 2 + +[[ -n "$POOL_HASH" ]] || die "failed to install farming-pool WASM (empty hash returned)" + +echo "Deploying factory..." +FACTORY_ID="$( + run_stellar stellar contract deploy \ + --wasm "$FACTORY_WASM" \ + --network "$NETWORK" \ + --source "$SOURCE" \ + --quiet +)" +sleep 2 + +[[ -n "$FACTORY_ID" ]] || die "failed to deploy factory (empty contract id returned)" + +echo "Initializing factory..." +if ! run_stellar stellar contract invoke \ + --id "$FACTORY_ID" \ + --network "$NETWORK" \ + --source "$SOURCE" \ + --quiet \ + -- initialize --admin "$ADMIN" --pool_wasm_hash "$POOL_HASH" >/dev/null; then + die "failed to initialize factory $FACTORY_ID" +fi + +printf '{"factory": "%s", "pool_wasm_hash": "%s", "network": "%s"}\n' \ + "$FACTORY_ID" "$POOL_HASH" "$NETWORK" >"$CONTRACT_IDS_FILE" + +echo "Deployment complete." +echo " factory: $FACTORY_ID" +echo " pool_wasm_hash: $POOL_HASH" +echo " saved to: $CONTRACT_IDS_FILE" diff --git a/stellar.toml b/stellar.toml new file mode 100644 index 0000000..5e2170f --- /dev/null +++ b/stellar.toml @@ -0,0 +1,7 @@ +[testnet] +rpc-url = "https://soroban-testnet.stellar.org" +network-passphrase = "Test SDF Network ; September 2015" + +[mainnet] +rpc-url = "https://soroban-rpc.stellar.org" +network-passphrase = "Public Global Stellar Network ; September 2015"