Jelajahi Sumber

CI: Move everything to a makefile (#81)

* CI: Move everything to a makefile

#### Problem

The transfer-hook repository is still using a collection of scripts, and
not a Makefile with reusable workflows.

#### Summary of changes

Transition everything to the Makefile and reusable workflows. Since
there aren't any JS clients in this repo, we can completely remove all
references to JS.

* Add an empty generate:clients step

* Gate program tests on required feature

* Remove test-sbf feature

* Delete unused setup action
Jon C 1 bulan lalu
induk
melakukan
935a641ae4

+ 0 - 137
.github/actions/setup/action.yml

@@ -1,137 +0,0 @@
-name: Setup environment
-
-inputs:
-  cargo-cache-key:
-    description: The key to cache cargo dependencies. Skips cargo caching if not provided.
-    required: false
-  cargo-cache-fallback-key:
-    description: The fallback key to use when caching cargo dependencies. Default to not using a fallback key.
-    required: false
-  cargo-cache-local-key:
-    description: The key to cache local cargo dependencies. Skips local cargo caching if not provided.
-    required: false
-  clippy:
-    description: Install Clippy if `true`. Defaults to `false`.
-    required: false
-  rustfmt:
-    description: Install Rustfmt if `true`. Defaults to `false`.
-    required: false
-  solana:
-    description: Install Solana if `true`. Defaults to `false`.
-    required: false
-  cli:
-    description: Install CLI dependencies if `true`. Defaults to `false`.
-    required: false
-  purge:
-    description: Purge unused directories if `true`. Defaults to `false`.
-    required: false
-
-runs:
-  using: 'composite'
-  steps:
-    - name: Setup pnpm
-      uses: pnpm/action-setup@v4
-
-    - name: Setup Node.js
-      uses: actions/setup-node@v4
-      with:
-        node-version: 20
-        cache: 'pnpm'
-
-    - name: Purge unused ubuntu runner directories
-      if: ${{ inputs.purge == 'true' }}
-      shell: bash
-      run: |
-        # If there are still disk space issues, try to add more packages from
-        # https://github.com/jlumbroso/free-disk-space
-        sudo rm -rf /usr/share/dotnet
-        sudo rm -rf /usr/share/swift
-        sudo rm -rf /usr/share/mysql
-        sudo rm -rf /usr/share/az_*
-        sudo rm -rf /usr/share/postgresql-common
-        sudo rm -rf /opt/ghc
-        sudo rm -rf /opt/az
-        sudo rm -rf /opt/pipx
-        sudo rm -rf /opt/microsoft
-        sudo rm -rf /opt/google
-        sudo rm -rf /opt/hostedtoolcache
-        sudo rm -rf /usr/local/lib/android
-        sudo rm -rf /usr/local/lib/heroku
-        sudo rm -rf /imagegeneration
-        sudo rm -rf "$AGENT_TOOLSDIRECTORY"
-        sudo docker image prune --all --force
-
-    - name: Install Dependencies
-      run: pnpm install --frozen-lockfile
-      shell: bash
-
-    - name: Set Environment Variables
-      shell: bash
-      run: pnpm zx ./scripts/ci/set-env.mjs
-
-    - name: Install Rustfmt
-      if: ${{ inputs.rustfmt == 'true' }}
-      uses: dtolnay/rust-toolchain@master
-      with:
-        toolchain: ${{ env.TOOLCHAIN_FORMAT }}
-        components: rustfmt
-
-    - name: Install Clippy
-      if: ${{ inputs.clippy == 'true' }}
-      uses: dtolnay/rust-toolchain@master
-      with:
-        toolchain: ${{ env.TOOLCHAIN_LINT }}
-        components: clippy
-
-    - name: Install Solana
-      if: ${{ inputs.solana == 'true' }}
-      uses: solana-program/actions/install-solana@v1
-      with:
-        version: ${{ env.SOLANA_VERSION }}
-        cache: true
-
-    - name: Install CLI dependencies
-      if: ${{ inputs.cli == 'true' }}
-      shell: bash
-      run: sudo apt update && sudo apt install libudev-dev protobuf-compiler libclang-dev -y
-
-    - name: Cache Cargo Dependencies
-      if: ${{ inputs.cargo-cache-key && !inputs.cargo-cache-fallback-key }}
-      uses: actions/cache@v4
-      with:
-        path: |
-          ~/.cargo/bin/
-          ~/.cargo/registry/index/
-          ~/.cargo/registry/cache/
-          ~/.cargo/git/db/
-          target/
-        key: ${{ runner.os }}-${{ inputs.cargo-cache-key }}-${{ hashFiles('**/Cargo.lock') }}
-        restore-keys: ${{ runner.os }}-${{ inputs.cargo-cache-key }}
-
-    - name: Cache Cargo Dependencies With Fallback
-      if: ${{ inputs.cargo-cache-key && inputs.cargo-cache-fallback-key }}
-      uses: actions/cache@v4
-      with:
-        path: |
-          ~/.cargo/bin/
-          ~/.cargo/registry/index/
-          ~/.cargo/registry/cache/
-          ~/.cargo/git/db/
-          target/
-        key: ${{ runner.os }}-${{ inputs.cargo-cache-key }}-${{ hashFiles('**/Cargo.lock') }}
-        restore-keys: |
-          ${{ runner.os }}-${{ inputs.cargo-cache-key }}
-          ${{ runner.os }}-${{ inputs.cargo-cache-fallback-key }}-${{ hashFiles('**/Cargo.lock') }}
-          ${{ runner.os }}-${{ inputs.cargo-cache-fallback-key }}
-
-    - name: Cache Local Cargo Dependencies
-      if: ${{ inputs.cargo-cache-local-key }}
-      uses: actions/cache@v4
-      with:
-        path: |
-          .cargo/bin/
-          .cargo/registry/index/
-          .cargo/registry/cache/
-          .cargo/git/db/
-        key: ${{ runner.os }}-${{ inputs.cargo-cache-local-key }}-${{ hashFiles('**/Cargo.lock') }}
-        restore-keys: ${{ runner.os }}-${{ inputs.cargo-cache-local-key }}

+ 38 - 190
.github/workflows/main.yml

@@ -6,194 +6,42 @@ on:
   pull_request:
     branches: [main]
 
-jobs:
-  format_and_lint_interface:
-    name: Format & Lint Interface
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          clippy: true
-          rustfmt: true
-          cargo-cache-key: cargo-interface-lint
-          cargo-cache-fallback-key: cargo-interface
-
-      - name: Format
-        run: pnpm interface:format
-
-      - name: Lint
-        run: pnpm interface:lint
-
-  format_and_lint_programs:
-    name: Format & Lint Programs
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          clippy: true
-          rustfmt: true
-          cargo-cache-key: cargo-programs-lint
-          cargo-cache-fallback-key: cargo-programs
-
-      - name: Format
-        run: pnpm programs:format
-
-      - name: Lint
-        run: pnpm programs:lint
-
-  format_and_lint_cli:
-    name: Format & Lint CLI
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          clippy: true
-          rustfmt: true
-          cli: true
-          cargo-cache-key: cargo-cli-lint
-          cargo-cache-fallback-key: cargo-cli
-
-      - name: Format
-        run: pnpm clients:cli:format
-
-      - name: Lint
-        run: pnpm clients:cli:lint
-
-  audit_rust:
-    name: Audit Rust
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-audit
-
-      - name: Install cargo-audit
-        uses: taiki-e/install-action@v2
-        with:
-          tool: cargo-audit
-
-      - name: Run cargo-audit
-        run: pnpm rust:audit
+env:
+  SBPF_PROGRAM_PACKAGES: "['program']"
+  RUST_PACKAGES: "['clients-cli', 'interface', 'program']"
+  WASM_PACKAGES: "['interface', 'program']"
 
-  spellcheck_rust:
-    name: Spellcheck Rust
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-spellcheck
-
-      - name: Install cargo-spellcheck
-        uses: taiki-e/install-action@v2
-        with:
-          tool: cargo-spellcheck
-
-      - name: Run cargo-spellcheck
-        run: pnpm rust:spellcheck
-
-  build_programs:
-    name: Build programs
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-programs
-          solana: true
-
-      - name: Build Program
-        run: pnpm programs:build
-
-      - name: Upload Program Builds
-        uses: actions/upload-artifact@v4
-        with:
-          name: program-builds
-          path: ./target/deploy/*.so
-          if-no-files-found: error
-
-      - name: Save Program Builds For Client Jobs
-        uses: actions/cache/save@v4
-        with:
-          path: ./target/deploy/*.so
-          key: ${{ runner.os }}-builds-${{ github.sha }}
-
-  test_interface:
-    name: Test Interface
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-interface-tests
-          cargo-cache-fallback-key: cargo-interface
-
-      - name: Test
-        run: pnpm interface:test
-
-  test_programs:
-    name: Test Programs
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-program-tests
-          cargo-cache-fallback-key: cargo-programs
-          solana: true
-          cli: true
-
-      - name: Test Programs
-        run: pnpm programs:test
-
-  test_client_cli:
-    name: Test CLI
-    runs-on: ubuntu-latest
-    needs: build_programs
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-cli-tests
-          cargo-cache-fallback-key: cargo-cli
-          cli: true
-
-      - name: Restore Program Builds
-        uses: actions/cache/restore@v4
-        with:
-          path: ./target/deploy/*.so
-          key: ${{ runner.os }}-builds-${{ github.sha }}
-
-      - name: Test
-        run: pnpm clients:cli:test
+jobs:
+  set_env:
+    name: Set variables to be used in strategy definitions in reusable workflow
+    runs-on: ubuntu-latest
+    outputs:
+      SBPF_PROGRAM_PACKAGES: ${{ steps.compute.outputs.SBPF_PROGRAM_PACKAGES }}
+      RUST_PACKAGES: ${{ steps.compute.outputs.RUST_PACKAGES }}
+      WASM_PACKAGES: ${{ steps.compute.outputs.WASM_PACKAGES }}
+      RUST_TOOLCHAIN_NIGHTLY: ${{ steps.compute.outputs.RUST_TOOLCHAIN_NIGHTLY }}
+      SOLANA_CLI_VERSION: ${{ steps.compute.outputs.SOLANA_CLI_VERSION }}
+    steps:
+      - name: Git Checkout
+        uses: actions/checkout@v4
+
+      - name: Compute variables
+        id: compute
+        shell: bash
+        run: |
+          echo "SBPF_PROGRAM_PACKAGES=${{ env.SBPF_PROGRAM_PACKAGES }}" >> $GITHUB_OUTPUT
+          echo "RUST_PACKAGES=${{ env.RUST_PACKAGES }}" >> $GITHUB_OUTPUT
+          echo "WASM_PACKAGES=${{ env.WASM_PACKAGES }}" >> $GITHUB_OUTPUT
+          echo "RUST_TOOLCHAIN_NIGHTLY=$(make rust-toolchain-nightly)" >> "$GITHUB_OUTPUT"
+          echo "SOLANA_CLI_VERSION=$(make solana-cli-version)" >> "$GITHUB_OUTPUT"
+
+  main:
+    needs: set_env
+    uses: solana-program/actions/.github/workflows/main.yml@main
+    with:
+      sbpf-program-packages: ${{ needs.set_env.outputs.SBPF_PROGRAM_PACKAGES }}
+      rust-packages: ${{ needs.set_env.outputs.RUST_PACKAGES }}
+      wasm-packages: ${{ needs.set_env.outputs.WASM_PACKAGES }}
+      rustfmt-toolchain: ${{ needs.set_env.outputs.RUST_TOOLCHAIN_NIGHTLY }}
+      clippy-toolchain: ${{ needs.set_env.outputs.RUST_TOOLCHAIN_NIGHTLY }}
+      solana-cli-version: ${{ needs.set_env.outputs.SOLANA_CLI_VERSION }}

+ 0 - 146
.github/workflows/publish-js-client.yml

@@ -1,146 +0,0 @@
-name: Publish JS Client
-
-on:
-  workflow_dispatch:
-    inputs:
-      package_path:
-        description: Path to directory with package to release
-        required: true
-        default: 'clients/js'
-        type: choice
-        options:
-          - clients/js
-          - clients/js-legacy
-      level:
-        description: Version level
-        required: true
-        default: patch
-        type: choice
-        options:
-          - patch
-          - minor
-          - major
-          - prerelease
-          - prepatch
-          - preminor
-          - premajor
-      tag:
-        description: NPM Tag (and preid for pre-releases)
-        required: true
-        type: string
-        default: latest
-      create_release:
-        description: Create a GitHub release
-        required: true
-        type: boolean
-        default: true
-
-jobs:
-  test:
-    name: Test JS package
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          solana: true
-          cargo-cache-key: cargo-js-test-publish-${{ inputs.package_path }}
-          cargo-cache-fallback-key: cargo-js-test-publish
-
-      - name: Format
-        run: pnpm zx ./scripts/js/format.mjs "${{ inputs.package_path }}"
-
-      - name: Lint
-        run: pnpm zx ./scripts/js/lint.mjs "${{ inputs.package_path }}"
-
-      - name: Build Program
-        run: pnpm programs:build
-
-      - name: Test
-        run: pnpm zx ./scripts/js/test.mjs "${{ inputs.package_path }}"
-
-  publish:
-    name: Publish JS package
-    runs-on: ubuntu-latest
-    needs: test
-    permissions:
-      contents: write
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-        with:
-          token: ${{ secrets.ANZA_TEAM_PAT }}
-          fetch-depth: 0 # get the whole history for git-cliff
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-
-      - name: Ensure SOLANA_NPM_TOKEN variable is set
-        env:
-          token: ${{ secrets.SOLANA_NPM_TOKEN }}
-        if: ${{ env.token == '' }}
-        run: |
-          echo "The SOLANA_NPM_TOKEN secret variable is not set"
-          echo "Go to \"Settings\" -> \"Secrets and variables\" -> \"Actions\" -> \"New repository secret\"."
-          exit 1
-
-      - name: Ensure SOLANA_PROGRAM_NPM_TOKEN variable is set
-        env:
-          token: ${{ secrets.SOLANA_PROGRAM_NPM_TOKEN }}
-        if: ${{ env.token == '' }}
-        run: |
-          echo "The SOLANA_PROGRAM_NPM_TOKEN secret variable is not set"
-          echo "Go to \"Settings\" -> \"Secrets and variables\" -> \"Actions\" -> \"New repository secret\"."
-          exit 1
-
-      - name: NPM Authentication
-        env:
-          SOLANA_NPM_TOKEN: ${{ secrets.SOLANA_NPM_TOKEN }}
-          SOLANA_PROGRAM_NPM_TOKEN: ${{ secrets.SOLANA_PROGRAM_NPM_TOKEN }}
-        shell: bash
-        run: |
-          cd "${{ inputs.package_path }}"
-          org="$(jq '.name|split("/")|.[0]' package.json)"
-          if [[ $org == "\"@solana-program\"" ]] then
-            pnpm config set '//registry.npmjs.org/:_authToken' "${SOLANA_PROGRAM_NPM_TOKEN}"
-          elif [[ $org == "\"@solana\"" ]] then
-            pnpm config set '//registry.npmjs.org/:_authToken' "${SOLANA_NPM_TOKEN}"
-          else
-            echo "Unknown organization: $org"
-            exit 1
-          fi
-
-      - name: Set Git Author
-        run: |
-          git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
-          git config --global user.name "github-actions[bot]"
-
-      - name: Publish JS Client
-        id: publish
-        run: pnpm js:publish "${{ inputs.package_path }}" ${{ inputs.level }} ${{ inputs.tag }}
-
-      - name: Push Commit and Tag
-        run: git push origin --follow-tags
-
-      - name: Generate a changelog
-        if: github.event.inputs.create_release == 'true'
-        uses: orhun/git-cliff-action@v3
-        with:
-          config: "scripts/cliff.toml"
-          args: |
-            "${{ steps.publish.outputs.old_git_tag }}"..main
-            --include-path "${{ inputs.package_path }}/**"
-            --github-repo "${{ github.repository }}"
-        env:
-          OUTPUT: TEMP_CHANGELOG.md
-          GITHUB_REPO: ${{ github.repository }}
-
-      - name: Create GitHub release
-        if: github.event.inputs.create_release == 'true'
-        uses: ncipollo/release-action@v1
-        with:
-          tag: ${{ steps.publish.outputs.new_git_tag }}
-          bodyFile: TEMP_CHANGELOG.md

+ 33 - 143
.github/workflows/publish-rust.yml

@@ -3,10 +3,10 @@ name: Publish Rust Crate
 on:
   workflow_dispatch:
     inputs:
-      package_path:
+      package-path:
         description: Path to directory with package to release
         required: true
-        default: 'interface'
+        default: 'clients/cli'
         type: choice
         options:
           - clients/cli
@@ -30,160 +30,50 @@ on:
         description: Version (used with level "version")
         required: false
         type: string
-      dry_run:
+      dry-run:
         description: Dry run
         required: true
         default: true
         type: boolean
-      create_release:
+      create-release:
         description: Create a GitHub release
         required: true
         type: boolean
         default: true
 
 jobs:
-  test:
-    name: Test Rust Crate
+  set_env:
+    name: Set variables to be used in strategy definitions
     runs-on: ubuntu-latest
+    outputs:
+      RUST_TOOLCHAIN_NIGHTLY: ${{ steps.compute.outputs.RUST_TOOLCHAIN_NIGHTLY }}
+      SOLANA_CLI_VERSION: ${{ steps.compute.outputs.SOLANA_CLI_VERSION }}
+      TARGET: ${{ steps.compute.outputs.TARGET }}
     steps:
       - name: Git Checkout
         uses: actions/checkout@v4
 
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          clippy: true
-          rustfmt: true
-          solana: true
-          cli: true
-          purge: true
-          cargo-cache-key: cargo-test-publish-${{ inputs.package_path }}
-          cargo-cache-fallback-key: cargo-test-publish
-
-      - name: Format
-        run: pnpm zx ./scripts/rust/format.mjs "${{ inputs.package_path }}"
-
-      - name: Lint
-        run: pnpm zx ./scripts/rust/lint.mjs "${{ inputs.package_path }}"
-
-      - name: Build programs
-        run: pnpm programs:build
-
-      - name: Test
-        run: pnpm zx ./scripts/rust/test.mjs "${{ inputs.package_path }}"
-
-  semver:
-    name: Check Semver
-    runs-on: ubuntu-latest
-    steps:
-      - name: Git checkout
-        if: ${{ inputs.package_path != 'clients/cli' }}
-        uses: actions/checkout@v4
-
-      - name: Setup Environment
-        if: ${{ inputs.package_path != 'clients/cli' }}
-        uses: ./.github/actions/setup
-        with:
-          cargo-cache-key: cargo-publish-semver-${{ inputs.package_path }}
-          cargo-cache-fallback-key: cargo-publish-semver
-
-      - name: Install cargo-semver-checks
-        if: ${{ inputs.package_path != 'clients/cli' }}
-        uses: taiki-e/install-action@v2
-        with:
-          tool: cargo-semver-checks,cargo-release
-
-      - name: Set Git Author (required for cargo-release)
-        if: ${{ inputs.package_path != 'clients/cli' }}
-        run: |
-          git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
-          git config --global user.name "github-actions[bot]"
-
-      - name: Set Version
-        if: ${{ inputs.package_path != 'clients/cli' }}
+      - name: Compute variables
+        id: compute
+        shell: bash
         run: |
-          if [ "${{ inputs.level }}" == "version" ]; then
-            LEVEL=${{ inputs.version }}
-          else
-            LEVEL=${{ inputs.level }}
-          fi
-          cargo release $LEVEL --manifest-path "${{ inputs.package_path }}/Cargo.toml" --no-tag --no-publish --no-push --no-confirm --execute
-
-      - name: Check semver
-        if: ${{ inputs.package_path != 'clients/cli' }}
-        run: pnpm rust:semver --manifest-path "${{ inputs.package_path }}/Cargo.toml"
-
-  publish:
-    name: Publish Rust Crate
-    runs-on: ubuntu-latest
-    needs: [test, semver]
-    permissions:
-      contents: write
-    steps:
-      - name: Git Checkout
-        uses: actions/checkout@v4
-        with:
-          token: ${{ secrets.ANZA_TEAM_PAT }}
-          fetch-depth: 0 # get the whole history for git-cliff
-
-      - name: Setup Environment
-        uses: ./.github/actions/setup
-        with:
-          cli: true
-          cargo-cache-key: cargo-publish-${{ inputs.package_path }}
-          cargo-cache-fallback-key: cargo-publish
-
-      - name: Install cargo-release
-        uses: taiki-e/install-action@v2
-        with:
-          tool: cargo-release
-
-      - name: Ensure CARGO_REGISTRY_TOKEN variable is set
-        env:
-          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
-        if: ${{ env.CARGO_REGISTRY_TOKEN == '' }}
-        run: |
-          echo "The CARGO_REGISTRY_TOKEN secret variable is not set"
-          echo "Go to \"Settings\" -> \"Secrets and variables\" -> \"Actions\" -> \"New repository secret\"."
-          exit 1
-
-      - name: Set Git Author
-        run: |
-          git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
-          git config --global user.name "github-actions[bot]"
-
-      - name: Publish Crate
-        id: publish
-        env:
-          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
-        run: |
-          if [ "${{ inputs.level }}" == "version" ]; then
-            LEVEL=${{ inputs.version }}
-          else
-            LEVEL=${{ inputs.level }}
-          fi
-
-          if [ "${{ inputs.dry_run }}" == "true" ]; then
-            OPTIONS="--dry-run"
-          else
-            OPTIONS=""
-          fi
-
-          pnpm rust:publish "${{ inputs.package_path }}" $LEVEL $OPTIONS
-
-      - name: Generate a changelog
-        if: github.event.inputs.create_release == 'true'
-        uses: orhun/git-cliff-action@v4
-        with:
-          config: "scripts/cliff.toml"
-          args: ${{ steps.publish.outputs.old_git_tag }}..HEAD --include-path "${{ inputs.package_path }}/**" --github-repo ${{ github.repository }}
-        env:
-          OUTPUT: TEMP_CHANGELOG.md
-          GITHUB_REPO: ${{ github.repository }}
-
-      - name: Create GitHub release
-        if: github.event.inputs.create_release == 'true' && github.event.inputs.dry_run != 'true'
-        uses: ncipollo/release-action@v1
-        with:
-          tag: ${{ steps.publish.outputs.new_git_tag }}
-          bodyFile: TEMP_CHANGELOG.md
+          echo "RUST_TOOLCHAIN_NIGHTLY=$(make rust-toolchain-nightly)" >> "$GITHUB_OUTPUT"
+          echo "SOLANA_CLI_VERSION=$(make solana-cli-version)" >> "$GITHUB_OUTPUT"
+          TARGET=$(echo ${{ inputs.package-path }} | sed 's#/#-#')
+          echo "TARGET=$TARGET" >> "$GITHUB_OUTPUT"
+
+  main:
+    needs: set_env
+    uses: solana-program/actions/.github/workflows/publish-rust.yml@main
+    with:
+      sbpf-program-packages: "program confidential-elgamal-registry"
+      solana-cli-version: ${{ needs.set_env.outputs.SOLANA_CLI_VERSION }}
+      clippy-toolchain: ${{ needs.set_env.outputs.RUST_TOOLCHAIN_NIGHTLY }}
+      rustfmt-toolchain: ${{ needs.set_env.outputs.RUST_TOOLCHAIN_NIGHTLY }}
+      target: ${{ needs.set_env.outputs.TARGET }}
+      package-path: ${{ inputs.package-path }}
+      level: ${{ inputs.level }}
+      version: ${{ inputs.version }}
+      create-release: ${{ inputs.create-release }}
+      dry-run: ${{ inputs.dry-run }}
+    secrets: inherit

+ 0 - 9
Cargo.toml

@@ -20,15 +20,6 @@ check-cfg = [
     'cfg(feature, values("frozen-abi", "no-entrypoint", "custom-heap", "custom-panic"))',
 ]
 
-[workspace.metadata.cli]
-solana = "3.0.0"
-
-# Specify Rust toolchains for rustfmt, clippy, and build.
-# Any unprovided toolchains default to stable.
-[workspace.metadata.toolchains]
-format = "nightly-2025-02-16"
-lint = "nightly-2025-02-16"
-
 [workspace.metadata.spellcheck]
 config = "scripts/spellcheck.toml"
 

+ 118 - 0
Makefile

@@ -0,0 +1,118 @@
+RUST_TOOLCHAIN_NIGHTLY = nightly-2025-02-16
+SOLANA_CLI_VERSION = 3.0.0
+
+nightly = +${RUST_TOOLCHAIN_NIGHTLY}
+
+# This is a bit tricky -- findstring returns the found string, so we're looking
+# for "directory-", returning that, and replacing "-" with "/" to change the
+# first "-" to a "/". But if it isn't found, we replace "" with "", which works
+# in the case where there is no subdirectory.
+pattern-dir = $(firstword $(subst -, ,$1))
+find-pattern-dir = $(findstring $(call pattern-dir,$1)-,$1)
+make-path = $(subst $(call find-pattern-dir,$1),$(subst -,/,$(call find-pattern-dir,$1)),$1)
+
+rust-toolchain-nightly:
+	@echo ${RUST_TOOLCHAIN_NIGHTLY}
+
+solana-cli-version:
+	@echo ${SOLANA_CLI_VERSION}
+
+cargo-nightly:
+	cargo $(nightly) $(ARGS)
+
+audit:
+	cargo audit \
+			--ignore RUSTSEC-2022-0093 \
+			--ignore RUSTSEC-2024-0421 \
+			--ignore RUSTSEC-2024-0344 \
+			--ignore RUSTSEC-2024-0376 $(ARGS)
+
+spellcheck:
+	cargo spellcheck --code 1 $(ARGS)
+
+clippy-%:
+	cargo $(nightly) clippy --manifest-path $(call make-path,$*)/Cargo.toml \
+	  --all-targets \
+		-- \
+		--deny=warnings \
+		--deny=clippy::default_trait_access \
+		--deny=clippy::arithmetic_side_effects \
+		--deny=clippy::manual_let_else \
+		--deny=clippy::used_underscore_binding $(ARGS)
+
+format-check-%:
+	cargo $(nightly) fmt --check --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+powerset-%:
+	cargo $(nightly) hack check --feature-powerset --all-targets --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+semver-check-%:
+	cargo semver-checks --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+shellcheck:
+	git ls-files -- '*.sh' | xargs shellcheck --color=always --external-sources --shell=bash $(ARGS)
+
+sort-check:
+	cargo $(nightly) sort --workspace --check $(ARGS)
+
+bench-%:
+	cargo $(nightly) bench --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+format-rust:
+	cargo $(nightly) fmt --all $(ARGS)
+
+build-sbf-%:
+	cargo build-sbf --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+build-wasm-%:
+	cargo build --target wasm32-unknown-unknown --manifest-path $(call make-path,$*)/Cargo.toml --all-features $(ARGS)
+
+build-doc-%:
+	RUSTDOCFLAGS="--cfg docsrs -D warnings" cargo $(nightly) doc --all-features --no-deps --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+test-doc-%:
+	cargo $(nightly) test --doc --all-features --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+test-%:
+	SBF_OUT_DIR=$(PWD)/target/deploy cargo $(nightly) test --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS)
+
+format-check-js-%:
+	cd $(call make-path,$*) && pnpm install && pnpm format $(ARGS)
+
+lint-js-%:
+	cd $(call make-path,$*) && pnpm install && pnpm lint $(ARGS)
+
+test-js-%:
+	make restart-test-validator
+	cd $(call make-path,$*) && pnpm install && pnpm build && pnpm test $(ARGS)
+	make stop-test-validator
+
+restart-test-validator:
+	./scripts/restart-test-validator.sh
+
+stop-test-validator:
+	pkill -f solana-test-validator
+
+generate-clients:
+	pnpm generate:clients $(ARGS)
+
+# Helpers for publishing
+tag-name = $(lastword $(subst /, ,$(call make-path,$1)))
+preid-arg = $(subst pre,--preid $2,$(findstring pre,$1))
+package-version = $(subst ",,$(shell jq -r '.version' $(call make-path,$1)/package.json))
+crate-version = $(subst ",,$(shell toml get $(call make-path,$1)/Cargo.toml package.version))
+
+git-tag-js-%:
+	@echo "$(call tag-name,$*)@v$(call package-version,$*)"
+
+publish-js-%:
+	cd "$(call make-path,$*)" && pnpm install && pnpm version $(LEVEL) --no-git-tag-version  $(call preid-arg,$(LEVEL),$(TAG)) && pnpm publish --no-git-checks --tag $(TAG)
+
+git-tag-rust-%:
+	@echo "$(call tag-name,$*)@v$(call crate-version,$*)"
+
+publish-rust-%:
+	cd "$(call make-path,$*)" && cargo release $(LEVEL) --tag-name "$(call tag-name,$*)@v{{version}}" --execute --no-confirm --dependent-version fix
+
+publish-rust-dry-run-%:
+	cd "$(call make-path,$*)" && cargo release $(LEVEL) --tag-name "$(call tag-name,$*)@v{{version}}"

+ 1 - 25
package.json

@@ -1,31 +1,7 @@
 {
   "private": true,
   "scripts": {
-    "programs:build": "zx ./scripts/rust/build-sbf.mjs program",
-    "programs:test": "zx ./scripts/rust/test-sbf.mjs program",
-    "programs:format": "zx ./scripts/rust/format.mjs program",
-    "programs:lint": "zx ./scripts/rust/lint.mjs program",
-    "solana:check": "zx ./scripts/check-solana-version.mjs",
-    "solana:link": "zx ./scripts/link-solana-version.mjs",
-    "validator:start": "zx ./scripts/start-validator.mjs",
-    "validator:restart": "pnpm validator:start --restart",
-    "validator:stop": "zx ./scripts/stop-validator.mjs",
-    "clients:cli:format": "zx ./scripts/rust/format.mjs clients/cli",
-    "clients:cli:lint": "zx ./scripts/rust/lint.mjs clients/cli",
-    "clients:cli:test": "zx ./scripts/rust/test.mjs clients/cli",
-    "template:upgrade": "zx ./scripts/upgrade-template.mjs",
-    "rust:spellcheck": "cargo spellcheck --code 1",
-    "rust:audit": "zx ./scripts/rust/audit.mjs",
-    "rust:semver": "cargo semver-checks",
-    "rust:publish": "zx ./scripts/rust/publish.mjs",
-    "interface:format": "zx ./scripts/rust/format.mjs interface",
-    "interface:lint": "zx ./scripts/rust/lint.mjs interface",
-    "interface:test": "zx ./scripts/rust/test.mjs interface"
-  },
-  "devDependencies": {
-    "@iarna/toml": "^2.2.5",
-    "typescript": "^5.5.2",
-    "zx": "^8.3.2"
+    "generate:clients": "exit 0"
   },
   "engines": {
     "node": ">=v20.0.0"

+ 1 - 34
pnpm-lock.yaml

@@ -6,37 +6,4 @@ settings:
 
 importers:
 
-  .:
-    devDependencies:
-      '@iarna/toml':
-        specifier: ^2.2.5
-        version: 2.2.5
-      typescript:
-        specifier: ^5.5.2
-        version: 5.8.2
-      zx:
-        specifier: ^8.3.2
-        version: 8.4.0
-
-packages:
-
-  '@iarna/toml@2.2.5':
-    resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
-
-  typescript@5.8.2:
-    resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==}
-    engines: {node: '>=14.17'}
-    hasBin: true
-
-  zx@8.4.0:
-    resolution: {integrity: sha512-b5+gbUT0akQ5vVuBuHgp0viQx2ZYCuooVD41Z7g47sN0diLsAvB2XteHcp5lec90CNEQ9o7TkXsE3ksaJrZHGw==}
-    engines: {node: '>= 12.17.0'}
-    hasBin: true
-
-snapshots:
-
-  '@iarna/toml@2.2.5': {}
-
-  typescript@5.8.2: {}
-
-  zx@8.4.0: {}
+  .: {}

+ 0 - 1
program/Cargo.toml

@@ -12,7 +12,6 @@ edition = { workspace = true }
 [features]
 default = ["forbid-additional-mints"]
 no-entrypoint = []
-test-sbf = []
 forbid-additional-mints = []
 
 [dependencies]

+ 1 - 1
program/tests/functional.rs

@@ -1,6 +1,6 @@
 // Mark this test as SBF-only due to current `ProgramTest` limitations when
 // CPIing into the system program
-#![cfg(feature = "test-sbf")]
+#![cfg(feature = "forbid-additional-mints")]
 
 use {
     solana_program_test::{processor, tokio, ProgramTest},

+ 0 - 24
scripts/check-solana-version.mjs

@@ -1,24 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import { getInstalledSolanaVersion, getSolanaVersion } from './utils.mjs';
-
-const expectedVersion = getSolanaVersion();
-const installedVersion = await getInstalledSolanaVersion();
-
-if (!installedVersion) {
-  echo(
-    chalk.red('[ ERROR ]'),
-    `No Solana installation found. Please install Solana ${expectedVersion} before proceeding.`
-  );
-  process.exit(1);
-} else if (installedVersion !== expectedVersion) {
-  echo(
-    chalk.yellow('[ WARNING ]'),
-    `The installed Solana version ${installedVersion} does not match the expected version ${expectedVersion}.`
-  );
-} else {
-  echo(
-    chalk.green('[ SUCCESS ]'),
-    `The expected Solana version ${expectedVersion} is installed.`
-  );
-}

+ 0 - 6
scripts/ci/set-env.mjs

@@ -1,6 +0,0 @@
-#!/usr/bin/env zx
-import { getSolanaVersion, getToolchain } from '../utils.mjs';
-
-await $`echo "SOLANA_VERSION=${getSolanaVersion()}" >> $GITHUB_ENV`;
-await $`echo "TOOLCHAIN_FORMAT=${getToolchain('format')}" >> $GITHUB_ENV`;
-await $`echo "TOOLCHAIN_LINT=${getToolchain('lint')}" >> $GITHUB_ENV`;

+ 0 - 28
scripts/generate-clients.mjs

@@ -1,28 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import { createFromRoot } from 'codama';
-import { renderVisitor as renderJavaScriptVisitor } from '@codama/renderers-js';
-// import { renderVisitor as renderRustVisitor } from "@codama/renderers-rust";
-import { workingDirectory } from './utils.mjs';
-
-// Instanciate Codama.
-const codama = createFromRoot(
-  require(path.join(workingDirectory, 'program', 'idl.json'))
-);
-
-// Render JavaScript.
-const jsClient = path.join(__dirname, '..', 'clients', 'js');
-codama.accept(
-  renderJavaScriptVisitor(path.join(jsClient, 'src', 'generated'), {
-    prettier: require(path.join(jsClient, '.prettierrc.json')),
-  })
-);
-
-// Render Rust.
-// const rustClient = path.join(__dirname, "..", "clients", "rust");
-// codama.accept(
-//   renderRustVisitor(path.join(rustClient, "src", "generated"), {
-//     formatCode: true,
-//     crateFolder: rustClient,
-//   })
-// );

+ 0 - 74
scripts/link-solana-version.mjs

@@ -1,74 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import { getInstalledSolanaVersion, getSolanaVersion } from './utils.mjs';
-
-const expectedVersion = getSolanaVersion();
-const installedVersion = await getInstalledSolanaVersion();
-
-const installPath = path.join(
-  os.homedir(),
-  '.local',
-  'share',
-  'solana',
-  'install'
-);
-const releasePath = path.join(
-  installPath,
-  'releases',
-  expectedVersion,
-  'solana-release'
-);
-const activeReleasePath = path.join(installPath, 'active_release');
-const hasRelease = await fs.exists(releasePath);
-
-if (!installedVersion) {
-  echo(
-    chalk.red('[ ERROR ]'),
-    `No Solana installation found. Solana ${expectedVersion} is required for this project.`
-  );
-  await askToInstallSolana(expectedVersion);
-} else if (installedVersion === expectedVersion) {
-  echo(
-    chalk.green('[ SUCCESS ]'),
-    `The expected Solana version ${expectedVersion} is installed.`
-  );
-} else if (hasRelease) {
-  await $`rm -f "${activeReleasePath}"`;
-  await $`ln -s "${releasePath}" "${activeReleasePath}"`;
-  echo(
-    chalk.green('[ SUCCESS ]'),
-    `Successfully switched from Solana version ${installedVersion} to ${expectedVersion} to match the project's requirements.`
-  );
-} else {
-  echo(
-    chalk.yellow('[ WARNING ]'),
-    `Cannot switch from Solana version ${installedVersion} to ${expectedVersion} because it is not installed.`
-  );
-  await askToInstallSolana(expectedVersion);
-}
-
-async function askToInstallSolana(version) {
-  const installRelease = await question('Should we install it now? [y/N] ');
-  if (installRelease === 'y') {
-    await installSolana(version);
-    echo(
-      chalk.green('[ SUCCESS ]'),
-      `Successfully installed Solana version ${version}.`
-    );
-  } else {
-    process.exit(1);
-  }
-}
-
-async function installSolana(version) {
-  echo(`Installing Solana ${version}...`);
-  const cutoff = '1.18.19';
-  const isBeforeCutoff =
-    (await $`[[ "$(printf '%s\n' "${cutoff}" "${version}" | sort -V | head -n1)" = "${version}" ]] && [[ "${cutoff}" != "${version}" ]]`.quiet()
-      .exitCode) == 0;
-  if (isBeforeCutoff) {
-    await $`sh -c "$(curl -sSfL https://release.solana.com/v${version}/install)"`;
-  } else {
-    await $`sh -c "$(curl -sSfL https://release.anza.xyz/v${version}/install)"`;
-  }
-}

+ 44 - 0
scripts/restart-test-validator.sh

@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+here="$(dirname "$0")"
+src_root="$(readlink -f "${here}/..")"
+cd "${src_root}"
+
+ARGS=(
+  -r
+  -q
+  --bpf-program TokenHookExampLe8smaVNrxTBezWTRbEwxwb1Zykrb ./target/deploy/spl_transfer_hook_example.so
+)
+PORT=8899
+PID=$(lsof -t -i:$PORT)
+
+if [ -n "$PID" ]; then
+  echo "Detected test validator running on PID $PID. Restarting..."
+  kill "$PID"
+  sleep 1
+fi
+
+echo "Starting Solana test validator..."
+solana-test-validator "${ARGS[@]}" &
+VALIDATOR_PID=$!
+
+# Wait for test validator to move past slot 0.
+echo -n "Waiting for validator to stabilize"
+for i in {1..8}; do
+  if ! kill -0 "$VALIDATOR_PID" 2>/dev/null; then
+    echo -e "\nTest validator exited early."
+    exit 1
+  fi
+
+  SLOT=$(solana slot -ul 2>/dev/null)
+  if [[ "$SLOT" =~ ^[0-9]+$ ]] && [ "$SLOT" -gt 0 ]; then
+    echo -e "\nTest validator is ready. Slot: $SLOT"
+    exit 0
+  fi
+
+  echo -n "."
+  sleep 1
+done
+
+echo -e "\nTimed out waiting for test validator to stabilize."
+exit 1

+ 0 - 42
scripts/rust/audit.mjs

@@ -1,42 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-
-const advisories = [
-  // ed25519-dalek: Double Public Key Signing Function Oracle Attack
-  //
-  // Remove once repo upgrades to ed25519-dalek v2
-  'RUSTSEC-2022-0093',
-
-  // curve25519-dalek
-  //
-  // Remove once repo upgrades to curve25519-dalek v4
-  'RUSTSEC-2024-0344',
-
-  // Crate:     tonic
-  // Version:   0.9.2
-  // Title:     Remotely exploitable Denial of Service in Tonic
-  // Date:      2024-10-01
-  // ID:        RUSTSEC-2024-0376
-  // URL:       https://rustsec.org/advisories/RUSTSEC-2024-0376
-  // Solution:  Upgrade to >=0.12.3
-  'RUSTSEC-2024-0376',
-
-  // Crate:     idna
-  // Version:   0.1.5
-  // Title:     `idna` accepts Punycode labels that do not produce any non-ASCII when decoded
-  // Date:      2024-12-09
-  // ID:        RUSTSEC-2024-0421
-  // URL:       https://rustsec.org/advisories/RUSTSEC-2024-0421
-  // Solution:  Upgrade to >=1.0.0
-  // need to solve this dependency tree:
-  // jsonrpc-core-client v18.0.0 -> jsonrpc-client-transports v18.0.0 -> url v1.7.2 -> idna v0.1.5
-  'RUSTSEC-2024-0421',
-];
-const ignores = []
-advisories.forEach(x => {
-  ignores.push('--ignore');
-  ignores.push(x);
-});
-
-// Check Solana version.
-await $`cargo audit ${ignores}`;

+ 0 - 10
scripts/rust/build-sbf.mjs

@@ -1,10 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import {
-  cliArguments,
-  workingDirectory,
-} from '../utils.mjs';
-
-const [folder, ...args] = cliArguments();
-const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml');
-await $`cargo-build-sbf --manifest-path ${manifestPath} ${args}`;

+ 0 - 23
scripts/rust/format.mjs

@@ -1,23 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import {
-  cliArguments,
-  getToolchainArgument,
-  partitionArguments,
-  popArgument,
-  workingDirectory,
-} from '../utils.mjs';
-
-const [folder, ...formatArgs] = cliArguments();
-
-const fix = popArgument(formatArgs, '--fix');
-const [cargoArgs, fmtArgs] = partitionArguments(formatArgs, '--');
-const toolchain = getToolchainArgument('format');
-
-const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml');
-
-if (fix) {
-  await $`cargo ${toolchain} fmt --manifest-path ${manifestPath} ${cargoArgs} -- ${fmtArgs}`;
-} else {
-  await $`cargo ${toolchain} fmt --manifest-path ${manifestPath} ${cargoArgs} -- --check ${fmtArgs}`;
-}

+ 0 - 32
scripts/rust/lint.mjs

@@ -1,32 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import {
-  cliArguments,
-  getToolchainArgument,
-  popArgument,
-  workingDirectory,
-} from '../utils.mjs';
-
-const [folder, ...args] = cliArguments();
-
-// Configure arguments here.
-const lintArgs = [
-  '-Zunstable-options',
-  '--all-targets',
-  '--all-features',
-  '--',
-  '--deny=warnings',
-  '--deny=clippy::arithmetic_side_effects',
-  ...args,
-];
-
-const fix = popArgument(lintArgs, '--fix');
-const toolchain = getToolchainArgument('lint');
-
-const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml');
-
-if (fix) {
-  await $`cargo ${toolchain} clippy --manifest-path ${manifestPath} --fix ${lintArgs}`;
-} else {
-  await $`cargo ${toolchain} clippy --manifest-path ${manifestPath} ${lintArgs}`;
-}

+ 0 - 41
scripts/rust/publish.mjs

@@ -1,41 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import { cliArguments, getCargo, workingDirectory } from '../utils.mjs';
-
-const dryRun = argv['dry-run'] ?? false;
-const [folder, level] = cliArguments();
-if (!folder) {
-  throw new Error('A path to a directory with a Rust package — e.g. "clients/cli" — must be provided.');
-}
-if (!level) {
-  throw new Error('A version level — e.g. "patch" — must be provided.');
-}
-
-cd(path.join(workingDirectory, folder));
-
-const packageToml = getCargo(folder).package;
-const oldVersion = packageToml.version;
-const packageName = packageToml.name;
-const tagName = path.basename(folder);
-
-// Publish the new version, commit the repo change, tag it, and push it all.
-const releaseArgs = dryRun
-  ? []
-  : ['--tag-name', `${tagName}@v{{version}}`, '--no-confirm', '--execute'];
-await $`cargo release ${level} ${releaseArgs}`;
-
-// Stop here if this is a dry run.
-if (dryRun) {
-  process.exit(0);
-}
-
-// Get the new version.
-const newVersion = getCargo(folder).package.version;
-const newGitTag = `${tagName}@v${newVersion}`;
-const oldGitTag = `${tagName}@v${oldVersion}`;
-
-// Expose the new version to CI if needed.
-if (process.env.CI) {
-  await $`echo "new_git_tag=${newGitTag}" >> $GITHUB_OUTPUT`;
-  await $`echo "old_git_tag=${oldGitTag}" >> $GITHUB_OUTPUT`;
-}

+ 0 - 11
scripts/rust/test-sbf.mjs

@@ -1,11 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import {
-  cliArguments,
-  workingDirectory,
-} from '../utils.mjs';
-
-const [folder, ...args] = cliArguments();
-const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml');
-
-await $`RUST_LOG=error cargo test-sbf --manifest-path ${manifestPath} ${args}`;

+ 0 - 12
scripts/rust/test.mjs

@@ -1,12 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import {
-  cliArguments,
-  workingDirectory,
-} from '../utils.mjs';
-
-const [folder, ...args] = cliArguments();
-const sbfOutDir = path.join(workingDirectory, 'target', 'deploy');
-const manifestPath = path.join(workingDirectory, folder, 'Cargo.toml');
-
-await $`RUST_LOG=error SBF_OUT_DIR=${sbfOutDir} cargo test --manifest-path ${manifestPath} ${args}`;

+ 8 - 0
scripts/solana.dic

@@ -61,3 +61,11 @@ Pedersen
 aes
 plaintext
 pausable
+u64
+pending_balance_credit_counter
+homomorphic
+homomorphically
+cryptographic
+cryptographically
+prover
+encryptions

+ 0 - 136
scripts/start-validator.mjs

@@ -1,136 +0,0 @@
-#!/usr/bin/env zx
-import { spawn } from 'node:child_process';
-import fs from 'node:fs';
-import 'zx/globals';
-import {
-  getCargo,
-  getExternalAccountAddresses,
-  getExternalProgramAddresses,
-  getExternalProgramOutputDir,
-  getProgramFolders,
-} from './utils.mjs';
-
-// Check Solana version.
-await $`pnpm solana:check`;
-
-// Options and arguments.
-const restart = argv['restart'];
-
-// Keep the validator running when not using the restart flag.
-const isValidatorRunning = (await $`lsof -t -i:8899`.quiet().exitCode) === 0;
-if (!restart && isValidatorRunning) {
-  echo(chalk.yellow('Local validator is already running.'));
-  process.exit();
-}
-
-// Dump external programs and accounts.
-await $`pnpm programs:dump`;
-
-// Initial message.
-const verb = isValidatorRunning ? 'Restarting' : 'Starting';
-
-// Get programs and accounts.
-const programs = [...getPrograms(), ...getExternalPrograms(), ...getFixturePrograms()];
-const programPluralized = programs.length === 1 ? 'program' : 'programs';
-const accounts = [...getExternalAccounts()];
-const accountsPluralized = accounts.length === 1 ? 'account' : 'accounts';
-
-echo(
-  `${verb} local validator with ${programs.length} custom ${programPluralized}` +
-    (accounts.length > 0
-      ? ` and ${accounts.length} external ${accountsPluralized}...`
-      : `...`)
-);
-
-// Kill the validator if it's already running.
-if (isValidatorRunning) {
-  await $`pkill -f solana-test-validator`.quiet();
-  await sleep(1000);
-}
-
-// Global validator arguments.
-const args = [/* Reset ledger */ '-r'];
-
-// Load programs.
-programs.forEach(({ programId, deployPath }) => {
-  args.push(/* Load BPF program */ '--bpf-program', programId, deployPath);
-});
-
-// Load accounts.
-accounts.forEach(({ account, deployPath }) => {
-  args.push(/* Load account */ '--account', account, deployPath);
-});
-
-// Start the validator in detached mode.
-const cliLogs = path.join(os.tmpdir(), 'validator-cli.log');
-fs.writeFileSync(cliLogs, '', () => {});
-const out = fs.openSync(cliLogs, 'a');
-const err = fs.openSync(cliLogs, 'a');
-const validator = spawn('solana-test-validator', args, {
-  detached: true,
-  stdio: ['ignore', out, err],
-});
-validator.unref();
-
-// Wait for the validator to stabilize.
-const waitForValidator = spinner(
-  'Waiting for local validator to stabilize...',
-  () =>
-    new Promise((resolve, reject) => {
-      setInterval(() => {
-        const logs = fs.readFileSync(cliLogs, 'utf8');
-        if (validator.exitCode !== null) {
-          reject(logs);
-        } else if (logs.includes('Confirmed Slot: 1')) {
-          resolve();
-        }
-      }, 1000);
-    })
-);
-
-try {
-  await waitForValidator;
-  echo(chalk.green('Local validator is up and running!'));
-} catch (error) {
-  echo(error);
-  echo(chalk.red('Could not start local validator.'));
-} finally {
-  fs.rmSync(cliLogs);
-  process.exit();
-}
-
-function getPrograms() {
-  const binaryDir = path.join(__dirname, '..', 'target', 'deploy');
-  return getProgramFolders().map((folder) => {
-    const cargo = getCargo(folder);
-    const name = cargo.package.name.replace(/-/g, '_');
-    return {
-      programId: cargo.package.metadata.solana['program-id'],
-      deployPath: path.join(binaryDir, `${name}.so`),
-    };
-  });
-}
-
-function getExternalPrograms() {
-  const binaryDir = getExternalProgramOutputDir();
-  return getExternalProgramAddresses().map((address) => ({
-    programId: address,
-    deployPath: path.join(binaryDir, `${address}.so`),
-  }));
-}
-
-function getFixturePrograms() {
-  const binaryDir = path.join(__dirname, '..', 'clients', 'rust-legacy', 'tests', 'fixtures');
-  return [{
-    programId: 'TokenHookExampLe8smaVNrxTBezWTRbEwxwb1Zykrb',
-    deployPath: path.join(binaryDir, 'spl_transfer_hook_example_no_default_features.so'),
-  }];
-}
-
-function getExternalAccounts() {
-  const binaryDir = getExternalProgramOutputDir();
-  return getExternalAccountAddresses().map((address) => ({
-    account: address,
-    deployPath: path.join(binaryDir, `${address}.json`),
-  }));
-}

+ 0 - 13
scripts/stop-validator.mjs

@@ -1,13 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-
-const isValidatorRunning = (await $`lsof -t -i:8899`.quiet().exitCode) === 0;
-
-if (isValidatorRunning) {
-  // Kill the validator if it's already running.
-  await $`pkill -f solana-test-validator`.quiet();
-  await sleep(1000);
-  echo(chalk.green('Local validator terminated!'));
-} else {
-  echo(chalk.yellow('Local validator is not running.'));
-}

+ 0 - 58
scripts/upgrade-template.mjs

@@ -1,58 +0,0 @@
-#!/usr/bin/env zx
-import 'zx/globals';
-import { getCargo } from './utils.mjs';
-
-// Arguments to pass to the `create-solana-program` command.
-const rustClientCargo = getCargo(path.join('clients', 'rust'));
-const jsClientPkg = require(
-  path.join(__dirname, '..', 'clients', 'js', 'package.json')
-);
-const templateArgs = [
-  'token-2022',
-  '--address',
-  'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb',
-  '--org',
-  'solana-program',
-  '--rust-client-crate-name',
-  rustClientCargo.package.name,
-  '--js-client-package-name',
-  jsClientPkg.name,
-  '--default',
-  '--force',
-];
-
-// File and folder patterns that should not be overwritten by the template upgrade.
-const unchangedGlobs = [
-  'clients/**/src/**',
-  'clients/**/src/*',
-  'clients/js/test/*',
-  'clients/rust/tests/*',
-  'program/**/*',
-  'program/*',
-  'scripts/generate-clients.mjs',
-  'scripts/generate-idls.mjs',
-  'scripts/upgrade-template.mjs',
-  'scripts/program/*',
-  'Cargo.lock',
-  '**/pnpm-lock.yaml',
-  'pnpm-lock.yaml',
-];
-
-// Prevent CLI arguments from being escaped.
-$.quote = (command) => command;
-
-// Re-generate the repo from the parent directory.
-cd('..');
-await $`pnpm create solana-program@latest ${templateArgs}`;
-
-// Go back inside the updated repo.
-cd('token-2022');
-
-// Restore files and folders that should not be overwritten.
-await $`git add --all`;
-for (const glob of unchangedGlobs) {
-  await $`git restore --worktree --staged "${glob}"`;
-}
-
-// Re-install dependencies.
-await $`pnpm install`;

+ 0 - 136
scripts/utils.mjs

@@ -1,136 +0,0 @@
-import 'zx/globals';
-import { parse as parseToml } from '@iarna/toml';
-
-process.env.FORCE_COLOR = 3;
-process.env.CARGO_TERM_COLOR = 'always';
-$.verbose = true;
-
-export const workingDirectory = (await $`pwd`.quiet()).toString().trim();
-
-export function getAllProgramIdls() {
-  return getAllProgramFolders().map((folder) =>
-    path.join(workingDirectory, folder, 'idl.json')
-  );
-}
-
-export function getExternalProgramOutputDir() {
-  const config = getCargoMetadata()?.solana?.['external-programs-output'];
-  return path.join(workingDirectory, config ?? 'target/deploy');
-}
-
-export function getExternalProgramAddresses() {
-  const addresses = getProgramFolders().flatMap(
-    (folder) => getCargoMetadata(folder)?.solana?.['program-dependencies'] ?? []
-  );
-  return Array.from(new Set(addresses));
-}
-
-export function getExternalAccountAddresses() {
-  const addresses = getProgramFolders().flatMap(
-    (folder) => getCargoMetadata(folder)?.solana?.['account-dependencies'] ?? []
-  );
-  return Array.from(new Set(addresses));
-}
-
-let didWarnAboutMissingPrograms = false;
-export function getProgramFolders() {
-  let programs;
-
-  if (process.env.PROGRAMS) {
-    try {
-      programs = JSON.parse(process.env.PROGRAMS);
-    } catch (error) {
-      programs = process.env.PROGRAMS.split(/\s+/);
-    }
-  } else {
-    programs = getAllProgramFolders();
-  }
-
-  const filteredPrograms = programs.filter((program) =>
-    fs.existsSync(path.join(workingDirectory, program))
-  );
-
-  if (
-    filteredPrograms.length !== programs.length &&
-    !didWarnAboutMissingPrograms
-  ) {
-    didWarnAboutMissingPrograms = true;
-    programs
-      .filter((program) => !filteredPrograms.includes(program))
-      .forEach((program) => {
-        echo(chalk.yellow(`Program not found: ${workingDirectory}/${program}`));
-      });
-  }
-
-  return filteredPrograms;
-}
-
-export function getAllProgramFolders() {
-  return getCargo().workspace.members.filter((member) =>
-    (getCargo(member).lib?.['crate-type'] ?? []).includes('cdylib')
-  );
-}
-
-export function getCargo(folder) {
-  return parseToml(
-    fs.readFileSync(
-      path.join(workingDirectory, folder ? folder : '.', 'Cargo.toml'),
-      'utf8'
-    )
-  );
-}
-
-export function getCargoMetadata(folder) {
-  const cargo = getCargo(folder);
-  return folder ? cargo?.package?.metadata : cargo?.workspace?.metadata;
-}
-
-export function getSolanaVersion() {
-  return getCargoMetadata()?.cli?.solana;
-}
-
-export function getToolchain(operation) {
-  return getCargoMetadata()?.toolchains?.[operation];
-}
-
-export function getToolchainArgument(operation) {
-  const channel = getToolchain(operation);
-  return channel ? `+${channel}` : '';
-}
-
-export function cliArguments() {
-  return process.argv.slice(3);
-}
-
-export function popArgument(args, arg) {
-  const index = args.indexOf(arg);
-  if (index >= 0) {
-    args.splice(index, 1);
-  }
-  return index >= 0;
-}
-
-export function partitionArguments(args, delimiter) {
-  const index = args.indexOf(delimiter);
-  return index >= 0
-    ? [args.slice(0, index), args.slice(index + 1)]
-    : [args, []];
-}
-
-export async function getInstalledSolanaVersion() {
-  try {
-    const { stdout } = await $`solana --version`.quiet();
-    return stdout.match(/(\d+\.\d+\.\d+)/)?.[1];
-  } catch (error) {
-    return '';
-  }
-}
-
-export function getPackageJson(folder) {
-  return JSON.parse(
-    fs.readFileSync(
-      path.join(workingDirectory, folder ? folder : '.', 'package.json'),
-      'utf8'
-    )
-  );
-}