diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..90a4d40 --- /dev/null +++ b/.env.example @@ -0,0 +1,49 @@ +# ============================================================ +# StellarSettle โ€“ Deployment environment variables +# Copy this file to .env and fill in your values. +# NEVER commit your real .env file to version control. +# ============================================================ + +# ----- Stellar network ----- +# Use "testnet", "mainnet", or "futurenet" +STELLAR_NETWORK=testnet + +# ----- Deployer identity ----- +# Secret key of the account that signs and pays for deployment. +# Starts with 'S' (e.g. SXXXXXโ€ฆ) +STELLAR_SECRET_KEY=SXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + +# Public key matching STELLAR_SECRET_KEY (starts with 'G'). +# Used as the admin address for all contracts. +ADMIN_PUBLIC_KEY=GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + +# ----- Platform fee ----- +# Fee in basis points (100 bps = 1%). Default: 300 = 3 % +PLATFORM_FEE_BPS=300 + +# ----- Invoice Token metadata ----- +# Human-readable name for the SEP-41 invoice token +INVOICE_TOKEN_NAME="StellarSettle Invoice Token" + +# Ticker symbol for the invoice token (max 12 chars recommended) +INVOICE_TOKEN_SYMBOL=SSINV + +# Decimal places for the invoice token (7 matches Stellar native asset) +INVOICE_TOKEN_DECIMALS=7 + +# Invoice identifier used when initialising the token contract. +# Must be a valid Soroban Symbol (โ‰ค32 chars, alphanumeric + underscore). +INVOICE_TOKEN_INVOICE_ID=INV001 + +# ----- WASM build output paths ----- +# Relative to the repo root (adjust if you use a custom release profile). +WASM_INVOICE_ESCROW=target/wasm32-unknown-unknown/release/invoice_escrow.wasm +WASM_INVOICE_TOKEN=target/wasm32-unknown-unknown/release/invoice_token.wasm +WASM_PAYMENT_DISTRIBUTOR=target/wasm32-unknown-unknown/release/payment_distributor.wasm + +# ----- (Optional) Pre-deployed contract IDs ----- +# Leave blank to let the scripts deploy fresh contracts. +# If set, the deploy step is skipped and only `initialize` is called. +INVOICE_ESCROW_CONTRACT_ID= +INVOICE_TOKEN_CONTRACT_ID= +PAYMENT_DISTRIBUTOR_CONTRACT_ID= diff --git a/.gitignore b/.gitignore index bbccbb1..507d06e 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,4 @@ tarpaulin-report.html debug/ # Maintainer-only GitHub issue tooling (not published) -/scripts/ +# NOTE: /scripts/ is intentionally NOT ignored โ€“ deployment scripts are public. diff --git a/Readme.md b/Readme.md index 39920bd..61936bf 100644 --- a/Readme.md +++ b/Readme.md @@ -52,22 +52,10 @@ soroban contract build ``` ### Deployment -```bash -# Deploy to testnet -soroban contract deploy \ - --wasm target/wasm32-unknown-unknown/release/invoice_escrow.wasm \ - --source YOUR_SECRET_KEY \ - --network testnet - -# Initialize contract -soroban contract invoke \ - --id CONTRACT_ID \ - --source YOUR_SECRET_KEY \ - --network testnet \ - -- initialize \ - --admin YOUR_PUBLIC_KEY \ - --platform_fee_bps 300 -``` + +Repeatable deployment scripts live in [`scripts/`](scripts/). See the [**How to run scripts**](#-how-to-run-scripts) section below for full instructions. + +The scripts deploy and initialise all three contracts in the correct order using environment variables. No manual copy-paste of WASM paths or contract IDs required. ## ๐Ÿ“š Contract Documentation @@ -101,6 +89,63 @@ pub fn record_payment( Full API documentation: [docs/API.md](docs/API.md) +## ๐Ÿ“œ How to run scripts + +### 1. Prerequisites + +- Soroban CLI installed (`cargo install --locked soroban-cli --features opt`) +- Contracts compiled: `soroban contract build` + +### 2. Configure environment variables + +```bash +# Copy the template and fill in your values +cp .env.example .env +$EDITOR .env # set STELLAR_SECRET_KEY, ADMIN_PUBLIC_KEY, STELLAR_NETWORK, etc. +``` + +See [`.env.example`](.env.example) for the full list of variables and their descriptions. + +> โš ๏ธ **Never commit `.env` to version control.** It is already listed in `.gitignore`. + +### 3a. Bash (macOS / Linux) + +```bash +# Run from the repo root +bash scripts/deploy.sh +``` + +The script: +1. Loads `.env` automatically +2. Validates all required variables and WASM paths +3. Deploys **invoice-token**, **invoice-escrow**, and **payment-distributor** in order +4. Calls `initialize` on each contract with the configured arguments +5. Prints a summary of deployed contract IDs + +### 3b. PowerShell (Windows) + +```powershell +# Allow script execution for this session (if not already set) +Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass + +# Run from the repo root +.\scripts\deploy.ps1 +``` + +The PowerShell script is functionally equivalent to the Bash script above. + +### Re-using existing contract IDs + +If a contract is already deployed and only needs re-initialisation, set its ID in `.env`: + +```dotenv +INVOICE_ESCROW_CONTRACT_ID=C... +INVOICE_TOKEN_CONTRACT_ID=C... +PAYMENT_DISTRIBUTOR_CONTRACT_ID=C... +``` + +The deploy step is skipped for any contract whose ID is pre-filled; `initialize` is still called. + ## ๐Ÿงช Testing ```bash # Run all tests @@ -124,6 +169,9 @@ cargo tarpaulin --out Html ## ๐Ÿ“Š Contract Addresses +> Contract IDs are printed at the end of each `deploy.sh` / `deploy.ps1` run. +> Update the values below after deploying. + ### Testnet - Invoice Escrow: `CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` - Invoice Token: `CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` diff --git a/scripts/deploy.ps1 b/scripts/deploy.ps1 new file mode 100644 index 0000000..2ce7236 --- /dev/null +++ b/scripts/deploy.ps1 @@ -0,0 +1,251 @@ +<# +.SYNOPSIS + StellarSettle โ€“ Contract Deployment Script (PowerShell) + +.DESCRIPTION + Deploys and initialises the following Soroban contracts: + 1. invoice-token (SEP-41 invoice tokenisation) + 2. invoice-escrow (escrow lifecycle + settlement) + 3. payment-distributor (automated payment distribution) + +.EXAMPLE + # 1. Copy .env.example to .env and fill in your values + Copy-Item .env.example .env + notepad .env # or your editor of choice + + # 2. Run from the repo root (allow script execution if needed) + Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass + .\scripts\deploy.ps1 + +.NOTES + Requirements: + - soroban-cli (cargo install --locked soroban-cli --features opt) + - Contracts already built: soroban contract build + Environment variables are loaded from .env (if present) or the current + shell environment. See .env.example for the full list. +#> + +#Requires -Version 5.1 +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +# --------------------------------------------------------------------------- +# Colour helpers +# --------------------------------------------------------------------------- +function Write-Info { param([string]$Msg) Write-Host "[INFO] $Msg" -ForegroundColor Cyan } +function Write-Ok { param([string]$Msg) Write-Host "[OK] $Msg" -ForegroundColor Green } +function Write-Warn { param([string]$Msg) Write-Host "[WARN] $Msg" -ForegroundColor Yellow } +function Write-Err { param([string]$Msg) Write-Host "[ERROR] $Msg" -ForegroundColor Red; exit 1 } + +# --------------------------------------------------------------------------- +# Locate the repo root (parent of the 'scripts' folder) +# --------------------------------------------------------------------------- +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$RepoRoot = Split-Path -Parent $ScriptDir + +# --------------------------------------------------------------------------- +# Load .env (if present) +# --------------------------------------------------------------------------- +$EnvFile = Join-Path $RepoRoot '.env' +if (Test-Path $EnvFile) { + Write-Info "Loading environment from $EnvFile" + Get-Content $EnvFile | ForEach-Object { + $line = $_.Trim() + # Skip comments and blank lines + if ($line -and -not $line.StartsWith('#')) { + $eqIdx = $line.IndexOf('=') + if ($eqIdx -gt 0) { + $key = $line.Substring(0, $eqIdx).Trim() + $value = $line.Substring($eqIdx + 1).Trim().Trim('"').Trim("'") + [System.Environment]::SetEnvironmentVariable($key, $value, 'Process') + } + } + } +} else { + Write-Warn '.env file not found โ€“ using environment variables already set in shell' +} + +# --------------------------------------------------------------------------- +# Read variables (with defaults where sensible) +# --------------------------------------------------------------------------- +function Require-Env { + param([string]$Name, [string]$Description) + $val = [System.Environment]::GetEnvironmentVariable($Name) + if ([string]::IsNullOrWhiteSpace($val)) { + Write-Err "Required environment variable '$Name' is not set. $Description" + } + return $val +} + +function Get-EnvOrDefault { + param([string]$Name, [string]$Default) + $val = [System.Environment]::GetEnvironmentVariable($Name) + if ([string]::IsNullOrWhiteSpace($val)) { return $Default } + return $val +} + +$StellarNetwork = Require-Env 'STELLAR_NETWORK' 'Use testnet, mainnet, or futurenet' +$StellarSecretKey = Require-Env 'STELLAR_SECRET_KEY' 'Deployer secret key (starts with S)' +$AdminPublicKey = Require-Env 'ADMIN_PUBLIC_KEY' 'Admin public key (starts with G)' +$PlatformFeeBps = Require-Env 'PLATFORM_FEE_BPS' 'Fee basis points (e.g. 300 = 3%)' +$InvoiceTokenName = Require-Env 'INVOICE_TOKEN_NAME' 'Human-readable token name' +$InvoiceTokenSymbol = Require-Env 'INVOICE_TOKEN_SYMBOL' 'Ticker symbol (โ‰ค12 chars)' +$InvoiceTokenDecimals = Require-Env 'INVOICE_TOKEN_DECIMALS' 'Decimal places (e.g. 7)' +$InvoiceTokenInvoiceId = Require-Env 'INVOICE_TOKEN_INVOICE_ID' 'Invoice identifier (Soroban Symbol)' + +$WasmInvoiceEscrow = Get-EnvOrDefault 'WASM_INVOICE_ESCROW' 'target/wasm32-unknown-unknown/release/invoice_escrow.wasm' +$WasmInvoiceToken = Get-EnvOrDefault 'WASM_INVOICE_TOKEN' 'target/wasm32-unknown-unknown/release/invoice_token.wasm' +$WasmPaymentDistributor = Get-EnvOrDefault 'WASM_PAYMENT_DISTRIBUTOR' 'target/wasm32-unknown-unknown/release/payment_distributor.wasm' + +$ExistingEscrowId = Get-EnvOrDefault 'INVOICE_ESCROW_CONTRACT_ID' '' +$ExistingTokenId = Get-EnvOrDefault 'INVOICE_TOKEN_CONTRACT_ID' '' +$ExistingDistributorId = Get-EnvOrDefault 'PAYMENT_DISTRIBUTOR_CONTRACT_ID' '' + +# --------------------------------------------------------------------------- +# Verify WASM files exist +# --------------------------------------------------------------------------- +Push-Location $RepoRoot + +foreach ($wasm in @($WasmInvoiceEscrow, $WasmInvoiceToken, $WasmPaymentDistributor)) { + if (-not (Test-Path $wasm)) { + Write-Err "WASM not found: $wasm`n Run 'soroban contract build' first." + } +} + +# --------------------------------------------------------------------------- +# Helper: deploy one contract +# --------------------------------------------------------------------------- +function Deploy-Contract { + param( + [string]$Label, + [string]$WasmPath, + [string]$ExistingId + ) + + if (-not [string]::IsNullOrWhiteSpace($ExistingId)) { + Write-Warn "$Label`: Skipping deploy โ€“ reusing existing ID: $ExistingId" + return $ExistingId + } + + Write-Info "Deploying $Label from $WasmPath ..." + $id = soroban contract deploy ` + --source $StellarSecretKey ` + --network $StellarNetwork ` + --wasm $WasmPath + + if ($LASTEXITCODE -ne 0) { + Write-Err "Deploy failed for $Label (exit code $LASTEXITCODE)" + } + + Write-Ok "$Label deployed โ†’ $id" + return $id.Trim() +} + +# --------------------------------------------------------------------------- +# 1. Deploy invoice-token +# --------------------------------------------------------------------------- +Write-Host "" +Write-Host "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Magenta +Write-Host " Step 1 / 3 โ€“ invoice-token" -ForegroundColor Magenta +Write-Host "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Magenta + +$InvoiceTokenId = Deploy-Contract 'invoice-token' $WasmInvoiceToken $ExistingTokenId + +# --------------------------------------------------------------------------- +# 2. Deploy invoice-escrow +# --------------------------------------------------------------------------- +Write-Host "" +Write-Host "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Magenta +Write-Host " Step 2 / 3 โ€“ invoice-escrow" -ForegroundColor Magenta +Write-Host "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Magenta + +$InvoiceEscrowId = Deploy-Contract 'invoice-escrow' $WasmInvoiceEscrow $ExistingEscrowId + +# --------------------------------------------------------------------------- +# 3. Deploy payment-distributor +# --------------------------------------------------------------------------- +Write-Host "" +Write-Host "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Magenta +Write-Host " Step 3 / 3 โ€“ payment-distributor" -ForegroundColor Magenta +Write-Host "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Magenta + +$PaymentDistributorId = Deploy-Contract 'payment-distributor' $WasmPaymentDistributor $ExistingDistributorId + +# --------------------------------------------------------------------------- +# Initialise contracts +# --------------------------------------------------------------------------- +Write-Host "" +Write-Host "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Magenta +Write-Host " Initialising contracts" -ForegroundColor Magenta +Write-Host "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Magenta + +# --- invoice-token.initialize --- +Write-Info "Initialising invoice-token ..." +Write-Info " admin = $AdminPublicKey" +Write-Info " name = $InvoiceTokenName" +Write-Info " symbol = $InvoiceTokenSymbol" +Write-Info " decimals = $InvoiceTokenDecimals" +Write-Info " invoice_id = $InvoiceTokenInvoiceId" +Write-Info " minter = $InvoiceEscrowId (escrow contract)" + +soroban contract invoke ` + --source $StellarSecretKey ` + --network $StellarNetwork ` + --id $InvoiceTokenId ` + -- initialize ` + --admin $AdminPublicKey ` + --name $InvoiceTokenName ` + --symbol $InvoiceTokenSymbol ` + --decimals $InvoiceTokenDecimals ` + --invoice_id $InvoiceTokenInvoiceId ` + --minter $InvoiceEscrowId + +if ($LASTEXITCODE -ne 0) { Write-Err "invoice-token initialization failed" } +Write-Ok "invoice-token initialised" + +# --- invoice-escrow.initialize --- +Write-Info "Initialising invoice-escrow ..." +Write-Info " admin = $AdminPublicKey" +Write-Info " platform_fee_bps = $PlatformFeeBps" + +soroban contract invoke ` + --source $StellarSecretKey ` + --network $StellarNetwork ` + --id $InvoiceEscrowId ` + -- initialize ` + --admin $AdminPublicKey ` + --platform_fee_bps $PlatformFeeBps + +if ($LASTEXITCODE -ne 0) { Write-Err "invoice-escrow initialization failed" } +Write-Ok "invoice-escrow initialised" + +# --- payment-distributor.initialize --- +Write-Info "Initialising payment-distributor ..." +Write-Info " admin = $AdminPublicKey" + +soroban contract invoke ` + --source $StellarSecretKey ` + --network $StellarNetwork ` + --id $PaymentDistributorId ` + -- initialize ` + --admin $AdminPublicKey + +if ($LASTEXITCODE -ne 0) { Write-Err "payment-distributor initialization failed" } +Write-Ok "payment-distributor initialised" + +# --------------------------------------------------------------------------- +# Summary +# --------------------------------------------------------------------------- +Write-Host "" +Write-Host "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Green +Write-Host " Deployment complete ๐Ÿš€" -ForegroundColor Green +Write-Host "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" -ForegroundColor Green +Write-Host (" {0,-28} {1}" -f "invoice-token:", $InvoiceTokenId) +Write-Host (" {0,-28} {1}" -f "invoice-escrow:", $InvoiceEscrowId) +Write-Host (" {0,-28} {1}" -f "payment-distributor:", $PaymentDistributorId) +Write-Host "" +Write-Host " Network: $StellarNetwork" +Write-Host "" +Write-Warn "Copy the contract IDs above into README.md โ†’ Contract Addresses." + +Pop-Location diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100755 index 0000000..f0ac57e --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,230 @@ +#!/usr/bin/env bash +# ============================================================================= +# StellarSettle โ€“ Contract Deployment Script (Bash) +# ============================================================================= +# +# Deploys and initialises the following Soroban contracts: +# 1. invoice-token (SEP-41 invoice tokenisation) +# 2. invoice-escrow (escrow lifecycle + settlement) +# 3. payment-distributor (automated payment distribution) +# +# Usage: +# # 1. Copy .env.example to .env and fill in your values +# cp .env.example .env && $EDITOR .env +# +# # 2. Run from the repo root +# bash scripts/deploy.sh +# +# Environment variables (loaded from .env if present, or set externally): +# See .env.example for the full list and documentation. +# +# Requirements: +# - soroban-cli (cargo install --locked soroban-cli --features opt) +# - Contracts already built: soroban contract build +# ============================================================================= + +set -euo pipefail + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- +RED='\033[0;31m' +GREEN='\033[0;32m' +CYAN='\033[0;36m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Colour + +info() { echo -e "${CYAN}[INFO]${NC} $*"; } +success() { echo -e "${GREEN}[OK]${NC} $*"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +die() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; } + +# --------------------------------------------------------------------------- +# Load .env (if present) +# --------------------------------------------------------------------------- +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +ENV_FILE="${REPO_ROOT}/.env" +if [[ -f "${ENV_FILE}" ]]; then + info "Loading environment from ${ENV_FILE}" + # Export variables, skipping comments and blank lines + set -o allexport + # shellcheck disable=SC1090 + source "${ENV_FILE}" + set +o allexport +else + warn ".env file not found โ€“ using environment variables already set in shell" +fi + +# --------------------------------------------------------------------------- +# Validate required variables +# --------------------------------------------------------------------------- +: "${STELLAR_NETWORK:? Set STELLAR_NETWORK (testnet | mainnet | futurenet)}" +: "${STELLAR_SECRET_KEY:? Set STELLAR_SECRET_KEY to your deployer secret key}" +: "${ADMIN_PUBLIC_KEY:? Set ADMIN_PUBLIC_KEY to the corresponding public key}" +: "${PLATFORM_FEE_BPS:? Set PLATFORM_FEE_BPS (e.g. 300 for 3%)}" +: "${INVOICE_TOKEN_NAME:? Set INVOICE_TOKEN_NAME}" +: "${INVOICE_TOKEN_SYMBOL:? Set INVOICE_TOKEN_SYMBOL}" +: "${INVOICE_TOKEN_DECIMALS:? Set INVOICE_TOKEN_DECIMALS}" +: "${INVOICE_TOKEN_INVOICE_ID:? Set INVOICE_TOKEN_INVOICE_ID}" + +WASM_INVOICE_ESCROW="${WASM_INVOICE_ESCROW:-target/wasm32-unknown-unknown/release/invoice_escrow.wasm}" +WASM_INVOICE_TOKEN="${WASM_INVOICE_TOKEN:-target/wasm32-unknown-unknown/release/invoice_token.wasm}" +WASM_PAYMENT_DISTRIBUTOR="${WASM_PAYMENT_DISTRIBUTOR:-target/wasm32-unknown-unknown/release/payment_distributor.wasm}" + +# --------------------------------------------------------------------------- +# Verify WASM artifacts exist +# --------------------------------------------------------------------------- +cd "${REPO_ROOT}" + +for wasm in "${WASM_INVOICE_ESCROW}" "${WASM_INVOICE_TOKEN}" "${WASM_PAYMENT_DISTRIBUTOR}"; do + if [[ ! -f "${wasm}" ]]; then + die "WASM not found: ${wasm}\n Run 'soroban contract build' first." + fi +done + +# --------------------------------------------------------------------------- +# Shared soroban-cli flags +# --------------------------------------------------------------------------- +SOROBAN_FLAGS=( + --source "${STELLAR_SECRET_KEY}" + --network "${STELLAR_NETWORK}" +) + +# --------------------------------------------------------------------------- +# deploy_contract