From 37bfa5030309751a5fdaa9603e1b099febaf9b4c Mon Sep 17 00:00:00 2001 From: hedun Date: Thu, 25 Jun 2026 11:04:08 +0100 Subject: [PATCH] feat: add token deployment script and documentation for stellar testnet --- deployments/deploy-token-testnet.md | 202 ++++++++++++++++++++++++++++ deployments/deploy-token-testnet.sh | 199 +++++++++++++++++++++++++++ deployments/token-deployment.json | 12 ++ 3 files changed, 413 insertions(+) create mode 100644 deployments/deploy-token-testnet.md create mode 100755 deployments/deploy-token-testnet.sh create mode 100644 deployments/token-deployment.json diff --git a/deployments/deploy-token-testnet.md b/deployments/deploy-token-testnet.md new file mode 100644 index 0000000..cc8c20a --- /dev/null +++ b/deployments/deploy-token-testnet.md @@ -0,0 +1,202 @@ +# Deploy Token Contract to Stellar Testnet + +This guide documents the steps to build and deploy the `bc-forge-token` contract to the Stellar Soroban Testnet. + +## Prerequisites + +- **Stellar CLI** (`stellar`) installed (v22+) — `cargo install --locked stellar-cli` +- Rust toolchain with `wasm32-unknown-unknown` target — `rustup target add wasm32-unknown-unknown` +- A Stellar Testnet account (auto-generated and funded by the deploy script) + +## Automated Deployment + +The fastest way to deploy is using the provided script: + +```bash +chmod +x deployments/deploy-token-testnet.sh +./deployments/deploy-token-testnet.sh +``` + +The script handles identity generation, funding, building, deploying, initializing, and verification automatically. It saves a deployment summary to `deployments/token-deployment.json`. + +### Environment Overrides + +| Variable | Default | Description | +|----------|---------|-------------| +| `IDENTITY` | `bc-forge-admin` | Named Stellar identity to use | +| `RPC_URL` | `https://soroban-testnet.stellar.org` | Soroban RPC endpoint | +| `NETWORK_PASSPHRASE` | `Test SDF Network ; September 2015` | Stellar network passphrase | +| `TOKEN_NAME` | `BCForge Token` | Token name for initialization | +| `TOKEN_SYMBOL` | `BCF` | Token symbol for initialization | +| `TOKEN_DECIMALS` | `7` | Token decimal precision | + +## Manual Deployment Steps + +### Step 1: Generate a Testnet Identity + +```bash +stellar keys generate bc-forge-admin --network testnet +stellar keys address bc-forge-admin +``` + +### Step 2: Fund via Friendbot + +```bash +curl "https://friendbot.stellar.org?addr=$(stellar keys address bc-forge-admin)" +``` + +### Step 3: Build the WASM Contract + +```bash +cargo build --target wasm32-unknown-unknown --release -p bc-forge-token +``` + +The WASM binary is output to: + +``` +target/wasm32-unknown-unknown/release/bc_forge_token.wasm +``` + +Verify the build artifact: + +```bash +sha256sum target/wasm32-unknown-unknown/release/bc_forge_token.wasm +``` + +### Step 4: Optimize the WASM + +Soroban contracts must be optimized before deployment to remove unnecessary code and ensure compatibility: + +```bash +stellar contract optimize --wasm target/wasm32-unknown-unknown/release/bc_forge_token.wasm +``` + +This generates: + +``` +target/wasm32-unknown-unknown/release/bc_forge_token.optimized.wasm +``` + +### Step 5: Deploy the Token Contract + +```bash +stellar contract deploy \ + --wasm target/wasm32-unknown-unknown/release/bc_forge_token.optimized.wasm \ + --source bc-forge-admin \ + --network testnet \ + --inclusion-fee 100 +``` + +This outputs the **Contract ID** (a `C...` address), for example: + +``` +CDLZFC7SYJLNQRBMHWL64HE3ZAMUFDUIPJNP4IHMSCPLPXMDRYIKID2 +``` + +> **Note:** Save this contract ID — you will need it for initialization and invocation. + +### Step 6: Initialize the Contract + +```bash +stellar contract invoke \ + --id \ + --source bc-forge-admin \ + --network testnet \ + --inclusion-fee 100 \ + -- \ + initialize \ + --admin-address $(stellar keys address bc-forge-admin) \ + --decimal 7 \ + --name "BCForge Token" \ + --symbol "BCF" +``` + +### Step 7: Verify Deployment + +#### Check Token Name + +```bash +stellar contract invoke \ + --id \ + --source bc-forge-admin \ + --network testnet \ + -- \ + name +``` + +Expected output: `"BCForge Token"` + +#### Check Token Symbol + +```bash +stellar contract invoke \ + --id \ + --source bc-forge-admin \ + --network testnet \ + -- \ + symbol +``` + +Expected output: `"BCF"` + +#### Check Decimals + +```bash +stellar contract invoke \ + --id \ + --source bc-forge-admin \ + --network testnet \ + -- \ + decimals +``` + +Expected output: `7` + +#### Check Total Supply + +```bash +stellar contract invoke \ + --id \ + --source bc-forge-admin \ + --network testnet \ + -- \ + supply +``` + +Expected output: `"0"` (no tokens minted yet) + +#### Check Admin + +```bash +stellar contract invoke \ + --id \ + --source bc-forge-admin \ + --network testnet \ + -- \ + admin +``` + +Expected output: The admin's public key address. + +## Deployment Result + +| Field | Value | +|-------|-------| +| **Token Contract ID** | `` | +| **Admin Address** | `` | +| **Token Name** | BCForge Token | +| **Token Symbol** | BCF | +| **Decimals** | 7 | +| **Network** | Stellar Testnet | +| **RPC URL** | https://soroban-testnet.stellar.org | + +## Troubleshooting + +- **`HostError: Error(Contract, #1)`**: Contract already initialized. The `initialize` function can only be called once. +- **`HostError: Error(Contract, #2)`**: Contract not initialized. Call `initialize` first before any other function. +- **`HostError: Error(Contract, #3)`**: Invalid amount (≤ 0). Check your amount values. +- **`HostError: Error(Contract, #4)`**: Insufficient balance. The caller does not have enough tokens. +- **`HostError: Error(Contract, #5)`**: Insufficient allowance. The spender has not been approved to spend enough tokens. +- **`HostError: Error(Contract, #6)`**: Contract is paused. Call `unpause` first. +- **Friendbot rate limiting**: If Friendbot returns an error, wait a few seconds and retry, or use an already-funded account. +- **WASM not found**: Ensure `cargo build` completed successfully and the target is `wasm32-unknown-unknown`. diff --git a/deployments/deploy-token-testnet.sh b/deployments/deploy-token-testnet.sh new file mode 100755 index 0000000..b5f1973 --- /dev/null +++ b/deployments/deploy-token-testnet.sh @@ -0,0 +1,199 @@ +#!/usr/bin/env bash +# Deploy bc-forge-token contract to Stellar Testnet +# +# Usage: +# ./deployments/deploy-token-testnet.sh +# +# Prerequisites: +# - stellar CLI installed (cargo install --locked stellar-cli) +# - Rust wasm32-unknown-unknown target (rustup target add wasm32-unknown-unknown) +# +# The script will: +# 1. Generate (or reuse) a named testnet identity called "bc-forge-admin" +# 2. Fund it via Stellar Friendbot +# 3. Build the bc-forge-token WASM +# 4. Deploy the contract to testnet +# 5. Initialize the contract +# 6. Invoke name / symbol / decimals / supply to prove liveness +# 7. Save a JSON deployment summary to deployments/token-deployment.json + +set -euo pipefail + +# --------------------------------------------------------------------------- +# Config — all overridable via environment variables +# --------------------------------------------------------------------------- +IDENTITY="${IDENTITY:-bc-forge-admin}" +RPC_URL="${RPC_URL:-https://soroban-testnet.stellar.org}" +NETWORK_PASSPHRASE="${NETWORK_PASSPHRASE:-Test SDF Network ; September 2015}" +TOKEN_NAME="${TOKEN_NAME:-BCForge Token}" +TOKEN_SYMBOL="${TOKEN_SYMBOL:-BCF}" +TOKEN_DECIMALS="${TOKEN_DECIMALS:-7}" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" +cd "$PROJECT_DIR" + +echo "================================================================" +echo " bc-forge-token Testnet Deployment" +echo "================================================================" + +# --------------------------------------------------------------------------- +# Step 1: Ensure named identity exists +# --------------------------------------------------------------------------- +echo "" +echo "=== Step 1: Identity Setup ===" +if stellar keys address "$IDENTITY" &>/dev/null; then + echo "Identity '$IDENTITY' already exists." +else + echo "Generating new identity '$IDENTITY'..." + stellar keys generate "$IDENTITY" --network testnet +fi + +ADMIN_ADDRESS=$(stellar keys address "$IDENTITY") +echo "Admin address: $ADMIN_ADDRESS" + +# --------------------------------------------------------------------------- +# Step 2: Fund via Friendbot +# --------------------------------------------------------------------------- +echo "" +echo "=== Step 2: Funding via Friendbot ===" +FUND_RESPONSE=$(curl -s "https://friendbot.stellar.org?addr=${ADMIN_ADDRESS}") +if echo "$FUND_RESPONSE" | grep -q '"hash"'; then + echo "Friendbot funding successful." +elif echo "$FUND_RESPONSE" | grep -q 'already exists'; then + echo "Account already funded — continuing." +else + echo "Friendbot response: $FUND_RESPONSE" + echo "Warning: Friendbot may have failed. Proceeding anyway..." +fi + +# --------------------------------------------------------------------------- +# Step 3: Build the WASM +# --------------------------------------------------------------------------- +echo "" +echo "=== Step 3: Building WASM ===" +cargo build --target wasm32-unknown-unknown --release -p bc-forge-token + +WASM_PATH="target/wasm32-unknown-unknown/release/bc_forge_token.wasm" +if [ ! -f "$WASM_PATH" ]; then + echo "ERROR: WASM not found at $WASM_PATH" + exit 1 +fi + +echo "Optimizing WASM..." +stellar contract optimize --wasm "$WASM_PATH" +OPTIMIZED_WASM_PATH="target/wasm32-unknown-unknown/release/bc_forge_token.optimized.wasm" + +WASM_SIZE=$(stat -c%s "$OPTIMIZED_WASM_PATH") +WASM_SHA=$(sha256sum "$OPTIMIZED_WASM_PATH" | awk '{print $1}') +echo "WASM optimized: ${WASM_SIZE} bytes" +echo "SHA-256: $WASM_SHA" + +# --------------------------------------------------------------------------- +# Step 4: Deploy the contract +# --------------------------------------------------------------------------- +echo "" +echo "=== Step 4: Deploying Token Contract ===" +TOKEN_CONTRACT_ID=$(stellar contract deploy \ + --wasm "$OPTIMIZED_WASM_PATH" \ + --source "$IDENTITY" \ + --network testnet \ + --inclusion-fee 100) + +echo "Token Contract ID: $TOKEN_CONTRACT_ID" + +# --------------------------------------------------------------------------- +# Step 5: Initialize the contract +# --------------------------------------------------------------------------- +echo "" +echo "=== Step 5: Initializing Contract ===" +stellar contract invoke \ + --id "$TOKEN_CONTRACT_ID" \ + --source "$IDENTITY" \ + --network testnet \ + --inclusion-fee 100 \ + -- \ + initialize \ + --admin-address "$ADMIN_ADDRESS" \ + --decimal "$TOKEN_DECIMALS" \ + --name "$TOKEN_NAME" \ + --symbol "$TOKEN_SYMBOL" + +echo "Contract initialized." + +# --------------------------------------------------------------------------- +# Step 6: Verify — invoke read-only functions +# --------------------------------------------------------------------------- +echo "" +echo "=== Step 6: Verifying Deployment ===" + +echo "name:" +stellar contract invoke \ + --id "$TOKEN_CONTRACT_ID" \ + --source "$IDENTITY" \ + --network testnet \ + -- \ + name + +echo "symbol:" +stellar contract invoke \ + --id "$TOKEN_CONTRACT_ID" \ + --source "$IDENTITY" \ + --network testnet \ + -- \ + symbol + +echo "decimals:" +stellar contract invoke \ + --id "$TOKEN_CONTRACT_ID" \ + --source "$IDENTITY" \ + --network testnet \ + -- \ + decimals + +echo "supply:" +stellar contract invoke \ + --id "$TOKEN_CONTRACT_ID" \ + --source "$IDENTITY" \ + --network testnet \ + -- \ + supply + +echo "admin:" +stellar contract invoke \ + --id "$TOKEN_CONTRACT_ID" \ + --source "$IDENTITY" \ + --network testnet \ + -- \ + admin + +# --------------------------------------------------------------------------- +# Step 7: Save deployment summary +# --------------------------------------------------------------------------- +DEPLOYED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)" + +cat > "$SCRIPT_DIR/token-deployment.json" <