diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..448fcd5 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,27 @@ +{ + "name": "StellarForge Development Container", + "image": "mcr.microsoft.com/devcontainers/rust:1-1-bookworm", + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "22" + } + }, + "containerEnv": { + "STELLAR_CLI_VERSION": "27.1.0", + "STELLAR_CLI_SHA256": "9915fe63753d7154c26bb9e6410cf1d1ff9727a9b378e663c2790ab7a266af94" + }, + "postCreateCommand": "rustup toolchain install && rustup default \"$(sed -n 's/^channel = \"\\(.*\\)\"/\\1/p' rust-toolchain.toml)\" && curl -sSfL -o /tmp/stellar-cli.tar.gz \"https://github.com/stellar/stellar-cli/releases/download/v${STELLAR_CLI_VERSION}/stellar-cli-${STELLAR_CLI_VERSION}-x86_64-unknown-linux-gnu.tar.gz\" && echo \"${STELLAR_CLI_SHA256} /tmp/stellar-cli.tar.gz\" | sha256sum --check --strict && sudo tar xzf /tmp/stellar-cli.tar.gz -C /usr/local/bin stellar && rm /tmp/stellar-cli.tar.gz && cd sdk && npm ci", + "customizations": { + "vscode": { + "extensions": [ + "rust-lang.rust-analyzer", + "tamasfe.even-better-toml", + "esbenp.prettier-vscode", + "dbaeumer.vscode-eslint", + "ms-vscode.vscode-typescript-next", + "GitHub.vscode-pull-request-github", + "usernamehw.errorlens" + ] + } + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..7bec29e --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,46 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "make build", + "type": "shell", + "command": "make build", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": "$rustc", + "detail": "Build all Soroban WASM contracts" + }, + { + "label": "make lint", + "type": "shell", + "command": "make lint", + "group": "build", + "problemMatcher": "$rustc", + "detail": "Run Clippy linter across the Rust workspace" + }, + { + "label": "make test", + "type": "shell", + "command": "make test", + "group": { + "kind": "test", + "isDefault": true + }, + "problemMatcher": "$rustc", + "detail": "Run all Rust contract tests" + }, + { + "label": "npm test", + "type": "shell", + "command": "npm test", + "options": { + "cwd": "${workspaceFolder}/sdk" + }, + "group": "test", + "problemMatcher": [], + "detail": "Run TypeScript SDK unit tests in sdk/" + } + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index c59d3d6..9fced6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `.devcontainer/devcontainer.json` with the pinned Rust toolchain (`rust-toolchain.toml`), `wasm32v1-none`, `stellar-cli` `27.1.0`, and Node.js 22 preinstalled, running `npm ci` in `sdk/` on creation (#81). +- `.vscode/tasks.json` defining `make build`, `make lint`, `make test`, and `npm test` grouped as build and test tasks (#82). +- `make doctor` target (`scripts/doctor.sh`) checking `rustc`, `wasm32v1-none`, `stellar-cli`, `node`, and `npm` versions against the repository's pinned expectations (#86). - `ci`: Add `contracts/size-budget.json` establishing tracked byte thresholds for each contract, enforced in `.github/workflows/contracts-ci.yml` (#94). - `ci`: Add `deny.toml` and `cargo-deny` check in `.github/workflows/security.yml` to enforce license compliance (Apache-2.0, MIT, BSD) and deny unknown registries (#91). - Stage 1 developer-experience tooling: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 46a892c..963b844 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -124,6 +124,9 @@ a weekly schedule. git clone https://github.com/0xLizTech/stellarforge.git cd stellarforge +# Verify required toolchain versions (rustc, wasm32v1-none, stellar-cli, node, npm) +make doctor + # Build everything make build @@ -137,6 +140,21 @@ make sdk-lint make sdk-typecheck ``` +### Devcontainer & Codespaces + +If you use GitHub Codespaces or the VS Code Dev Containers extension, `.devcontainer/devcontainer.json` provisions a ready-to-use environment with the pinned Rust toolchain (`rust-toolchain.toml`), the `wasm32v1-none` target, `stellar-cli` (`27.1.0`, matching CI), and Node.js 22 preinstalled, and runs `npm ci` in `sdk/` automatically on container creation so `make test` and `npm test` work immediately without manual setup. + +### VS Code Tasks + +`.vscode/tasks.json` defines Command Palette tasks (**Terminal: Run Task**) grouped into build and test tasks: + +| Task label | Group | Command | Description | +|---|---|---|---| +| `make build` | `build` (default) | `make build` | Build all Soroban WASM contracts | +| `make lint` | `build` | `make lint` | Run Clippy linter across the Rust workspace | +| `make test` | `test` (default) | `make test` | Run all Rust contract tests | +| `npm test` | `test` | `npm test` (in `sdk/`) | Run TypeScript SDK unit tests | + ### Running a single contract's tests ```bash @@ -173,7 +191,8 @@ stellarforge/ │ ├── registry/ # Global registry of deployed asset contracts │ ├── compliance/ # KYC/AML record management │ ├── governance/ # On-chain proposal & voting -│ └── oracle-adapter/ # SEP-40 NAV price feed (Phase 2) +│ ├── oracle-adapter/ # SEP-40 NAV price feed (Phase 2) +│ └── vault/ # Fractionalization vault & SEP-41 share token (Phase 2) ├── sdk/ # @stellarforge-protocol/sdk (TypeScript) │ ├── src/ │ │ ├── client.ts # RwaAssetClient, ComplianceClient diff --git a/Makefile b/Makefile index bf4a9fd..8be8564 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: all build test fmt lint clean sdk-install sdk-build sdk-test sdk-lint sdk-typecheck deploy-testnet udeps hooks help +.PHONY: all build test fmt lint clean sdk-install sdk-build sdk-test sdk-lint sdk-typecheck deploy-testnet udeps hooks doctor help # ─── Variables ──────────────────────────────────────────────────────────────── NETWORK ?= testnet @@ -61,6 +61,9 @@ hooks: ## Install the pre-commit Git hooks (install: pip install pre-commit) pre-commit install --hook-type commit-msg @echo "Pre-commit hooks installed. Run 'pre-commit run --all-files' to check the tree." +doctor: ## Check local Rust, stellar-cli, and Node toolchain against pinned versions + ./scripts/doctor.sh + ##@ Release deploy-testnet: ## Deploy all four contracts to Stellar testnet @echo "Deploying all four contracts to Stellar testnet..." diff --git a/scripts/doctor.sh b/scripts/doctor.sh new file mode 100755 index 0000000..af653f0 --- /dev/null +++ b/scripts/doctor.sh @@ -0,0 +1,127 @@ +#!/usr/bin/env bash +# doctor.sh — Verify that the local StellarForge development toolchain is +# installed and matches the versions pinned across the repository. +# +# Usage: +# make doctor +# ./scripts/doctor.sh +# +# Checks every required tool in one pass rather than stopping at the first +# failure, printing the expected version beside each result and exiting +# non-zero if anything is missing or mismatched. + +set -uo pipefail + +EXPECTED_RUSTC="1.98.1" +if [[ -f rust-toolchain.toml ]]; then + parsed_rustc=$(sed -n 's/^channel *= *"\([^"]*\)".*/\1/p' rust-toolchain.toml) + [[ -n "$parsed_rustc" ]] && EXPECTED_RUSTC="$parsed_rustc" +fi + +EXPECTED_WASM_TARGET="wasm32v1-none" +EXPECTED_STELLAR_CLI="27.1.0" +if [[ -f .github/workflows/contracts-ci.yml ]]; then + parsed_stellar=$(sed -n 's/^ *STELLAR_CLI_VERSION: *"\([^"]*\)".*/\1/p' .github/workflows/contracts-ci.yml) + [[ -n "$parsed_stellar" ]] && EXPECTED_STELLAR_CLI="$parsed_stellar" +fi + +EXPECTED_NODE_MIN="22.12.0" +EXPECTED_NPM_MIN="10.0.0" + +failures=0 + +pass() { + printf " [OK] %-18s %-20s (expected: %s)\n" "$1" "$2" "$3" +} + +fail() { + printf " [FAIL] %-18s %-20s (expected: %s)\n" "$1" "$2" "$3" >&2 + failures=$((failures + 1)) +} + +version_ge() { + local actual="$1" + local required="$2" + local IFS=. + local i a=($actual) r=($required) + for ((i = 0; i < ${#r[@]}; i++)); do + local av="${a[i]:-0}" + local rv="${r[i]:-0}" + if ((10#$av > 10#$rv)); then + return 0 + elif ((10#$av < 10#$rv)); then + return 1 + fi + done + return 0 +} + +echo "Checking StellarForge toolchain..." + +# 1. rustc +if command -v rustc >/dev/null 2>&1; then + rustc_ver=$(rustc --version 2>/dev/null | awk '{print $2}') + if [[ "$rustc_ver" == "$EXPECTED_RUSTC" ]]; then + pass "rustc" "$rustc_ver" "$EXPECTED_RUSTC" + else + fail "rustc" "${rustc_ver:-unknown}" "$EXPECTED_RUSTC" + fi +else + fail "rustc" "missing" "$EXPECTED_RUSTC" +fi + +# 2. wasm32v1-none target +if command -v rustup >/dev/null 2>&1; then + if rustup target list --installed 2>/dev/null | grep -qx "$EXPECTED_WASM_TARGET"; then + pass "wasm target" "$EXPECTED_WASM_TARGET" "$EXPECTED_WASM_TARGET installed" + else + fail "wasm target" "not installed" "$EXPECTED_WASM_TARGET installed" + fi +else + fail "wasm target" "rustup missing" "$EXPECTED_WASM_TARGET installed" +fi + +# 3. stellar-cli +if command -v stellar >/dev/null 2>&1; then + stellar_ver=$(stellar --version 2>/dev/null | head -n 1 | awk '{print $2}') + if [[ "$stellar_ver" == "$EXPECTED_STELLAR_CLI" ]]; then + pass "stellar-cli" "$stellar_ver" "$EXPECTED_STELLAR_CLI" + else + fail "stellar-cli" "${stellar_ver:-unknown}" "$EXPECTED_STELLAR_CLI" + fi +else + fail "stellar-cli" "missing" "$EXPECTED_STELLAR_CLI" +fi + +# 4. node +if command -v node >/dev/null 2>&1; then + node_ver=$(node --version 2>/dev/null | sed 's/^v//') + if [[ -n "$node_ver" ]] && version_ge "$node_ver" "$EXPECTED_NODE_MIN"; then + pass "node" "$node_ver" ">= $EXPECTED_NODE_MIN" + else + fail "node" "${node_ver:-unknown}" ">= $EXPECTED_NODE_MIN" + fi +else + fail "node" "missing" ">= $EXPECTED_NODE_MIN" +fi + +# 5. npm +if command -v npm >/dev/null 2>&1; then + npm_ver=$(npm --version 2>/dev/null | tr -d '[:space:]') + if [[ -n "$npm_ver" ]] && version_ge "$npm_ver" "$EXPECTED_NPM_MIN"; then + pass "npm" "$npm_ver" ">= $EXPECTED_NPM_MIN" + else + fail "npm" "${npm_ver:-unknown}" ">= $EXPECTED_NPM_MIN" + fi +else + fail "npm" "missing" ">= $EXPECTED_NPM_MIN" +fi + +if ((failures > 0)); then + echo "" >&2 + echo "doctor: $failures check(s) failed. See CONTRIBUTING.md for installation instructions." >&2 + exit 1 +fi + +echo "" +echo "All toolchain checks passed."