Skip to content

Merge pull request #921 from maztah1/docs/wave-contributor-guide #1

Merge pull request #921 from maztah1/docs/wave-contributor-guide

Merge pull request #921 from maztah1/docs/wave-contributor-guide #1

Workflow file for this run

name: Contract Deployment Pipeline
on:
push:
branches: [main, develop]
paths:
- 'contracts/**'
- 'scripts/deploy_*.sh'
- '.github/workflows/deploy.yml'
workflow_dispatch:
inputs:
network:
description: 'Target network'
required: true
type: choice
options: [testnet, mainnet]
rollback_artifact:
description: 'Artifact run ID to roll back to (leave empty for normal deploy)'
required: false
type: string
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: false # never cancel an in-flight deploy
env:
WASM_PATH: target/wasm32-unknown-unknown/release/stellar_save.wasm
WASM_SIZE_LIMIT_KB: 100
CONTRACT_NAME: stellar-save
# ─── Job 1: Pre-deployment validation ────────────────────────────────────────
jobs:
pre-deploy:
name: Pre-deployment Validation
runs-on: ubuntu-latest
outputs:
wasm_hash: ${{ steps.hash.outputs.wasm_hash }}
wasm_size_kb: ${{ steps.hash.outputs.wasm_size_kb }}
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
components: clippy
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
workspaces: ". -> target"
- name: Run pre-deployment checks
run: bash scripts/pre_deploy_check.sh
env:
WASM_SIZE_LIMIT_KB: ${{ env.WASM_SIZE_LIMIT_KB }}
- name: Build optimised WASM
run: |
cargo build \
--manifest-path contracts/stellar-save/Cargo.toml \
--target wasm32-unknown-unknown \
--release
- name: Compute WASM hash and size
id: hash
run: |
HASH=$(sha256sum "${{ env.WASM_PATH }}" | awk '{print $1}')
SIZE_KB=$(du -k "${{ env.WASM_PATH }}" | awk '{print $1}')
echo "wasm_hash=${HASH}" >> "$GITHUB_OUTPUT"
echo "wasm_size_kb=${SIZE_KB}" >> "$GITHUB_OUTPUT"
echo "WASM hash : ${HASH}"
echo "WASM size : ${SIZE_KB} KB"
- name: Upload WASM artifact
uses: actions/upload-artifact@v4
with:
name: wasm-${{ github.sha }}
path: ${{ env.WASM_PATH }}
retention-days: 90 # keep for rollback
# ─── Job 2: Deploy to Testnet ─────────────────────────────────────────────────
deploy-testnet:
name: Deploy → Testnet
needs: pre-deploy
runs-on: ubuntu-latest
if: |
github.ref == 'refs/heads/develop' ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.network == 'testnet')
environment:
name: testnet
url: https://stellar.expert/explorer/testnet
outputs:
contract_id: ${{ steps.deploy.outputs.contract_id }}
steps:
- uses: actions/checkout@v4
- name: Install Stellar CLI
run: |
curl -sSL https://github.com/stellar/stellar-cli/releases/download/v22.7.1/stellar-cli-22.7.1-x86_64-unknown-linux-gnu.tar.gz \
| tar -xz -C /usr/local/bin stellar
stellar --version
- name: Download WASM artifact
uses: actions/download-artifact@v4
with:
name: wasm-${{ github.sha }}
path: wasm-artifact
- name: Configure deployer identity
run: |
echo "${{ secrets.TESTNET_DEPLOYER_SECRET }}" \
| stellar keys add deployer --secret-key --stdin
env:
STELLAR_NETWORK: testnet
- name: Deploy contract
id: deploy
run: |
CONTRACT_ID=$(stellar contract deploy \
--wasm wasm-artifact/stellar_save.wasm \
--network testnet \
--source-account deployer \
--ignore-checks)
echo "contract_id=${CONTRACT_ID}" >> "$GITHUB_OUTPUT"
echo "Deployed contract ID: ${CONTRACT_ID}"
env:
STELLAR_NETWORK: testnet
- name: Verify deployment
run: bash scripts/verify_contract.sh
env:
STELLAR_NETWORK: testnet
STELLAR_RPC_URL: https://soroban-testnet.stellar.org
CONTRACT_ID: ${{ steps.deploy.outputs.contract_id }}
EXPECTED_WASM_HASH: ${{ needs.pre-deploy.outputs.wasm_hash }}
- name: Post-deploy smoke tests
run: bash scripts/smoke_test_post_deploy.sh
env:
STELLAR_NETWORK: testnet
STELLAR_RPC_URL: https://soroban-testnet.stellar.org
CONTRACT_ID: ${{ steps.deploy.outputs.contract_id }}
- name: Save deployment record
run: |
mkdir -p deployment-records
cat > deployment-records/testnet-${{ github.sha }}.json <<EOF
{
"network": "testnet",
"contract_id": "${{ steps.deploy.outputs.contract_id }}",
"wasm_hash": "${{ needs.pre-deploy.outputs.wasm_hash }}",
"wasm_size_kb": "${{ needs.pre-deploy.outputs.wasm_size_kb }}",
"commit": "${{ github.sha }}",
"deployed_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"deployed_by": "${{ github.actor }}"
}
EOF
cat deployment-records/testnet-${{ github.sha }}.json
- name: Upload deployment record
uses: actions/upload-artifact@v4
with:
name: deployment-record-testnet-${{ github.sha }}
path: deployment-records/
retention-days: 90
- name: Comment on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: [
'## ✅ Testnet Deployment',
`**Contract ID:** \`${{ steps.deploy.outputs.contract_id }}\``,
`**WASM hash:** \`${{ needs.pre-deploy.outputs.wasm_hash }}\``,
`**Explorer:** https://stellar.expert/explorer/testnet/contract/${{ steps.deploy.outputs.contract_id }}`
].join('\n')
});
# ─── Job 3: Deploy to Mainnet (requires manual approval via environment) ──────
deploy-mainnet:
name: Deploy → Mainnet
needs: pre-deploy
runs-on: ubuntu-latest
if: |
github.ref == 'refs/heads/main' ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.network == 'mainnet')
environment:
name: production # GitHub environment with required reviewers
url: https://stellar.expert/explorer/mainnet
outputs:
contract_id: ${{ steps.deploy.outputs.contract_id }}
steps:
- uses: actions/checkout@v4
- name: Install Stellar CLI
run: |
curl -sSL https://github.com/stellar/stellar-cli/releases/download/v22.7.1/stellar-cli-22.7.1-x86_64-unknown-linux-gnu.tar.gz \
| tar -xz -C /usr/local/bin stellar
stellar --version
- name: Download WASM artifact
uses: actions/download-artifact@v4
with:
name: wasm-${{ github.sha }}
path: wasm-artifact
- name: Configure deployer identity
run: |
echo "${{ secrets.MAINNET_DEPLOYER_SECRET }}" \
| stellar keys add deployer --secret-key --stdin
env:
STELLAR_NETWORK: mainnet
- name: Deploy contract
id: deploy
run: |
CONTRACT_ID=$(stellar contract deploy \
--wasm wasm-artifact/stellar_save.wasm \
--network mainnet \
--source-account deployer \
--ignore-checks)
echo "contract_id=${CONTRACT_ID}" >> "$GITHUB_OUTPUT"
echo "Deployed contract ID: ${CONTRACT_ID}"
env:
STELLAR_NETWORK: mainnet
- name: Verify deployment
run: bash scripts/verify_contract.sh
env:
STELLAR_NETWORK: mainnet
STELLAR_RPC_URL: https://soroban-rpc.mainnet.stellar.gateway.fm
CONTRACT_ID: ${{ steps.deploy.outputs.contract_id }}
EXPECTED_WASM_HASH: ${{ needs.pre-deploy.outputs.wasm_hash }}
- name: Post-deploy smoke tests
run: bash scripts/smoke_test_post_deploy.sh
env:
STELLAR_NETWORK: mainnet
STELLAR_RPC_URL: https://soroban-rpc.mainnet.stellar.gateway.fm
CONTRACT_ID: ${{ steps.deploy.outputs.contract_id }}
- name: Save deployment record
run: |
mkdir -p deployment-records
cat > deployment-records/mainnet-${{ github.sha }}.json <<EOF
{
"network": "mainnet",
"contract_id": "${{ steps.deploy.outputs.contract_id }}",
"wasm_hash": "${{ needs.pre-deploy.outputs.wasm_hash }}",
"wasm_size_kb": "${{ needs.pre-deploy.outputs.wasm_size_kb }}",
"commit": "${{ github.sha }}",
"deployed_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"deployed_by": "${{ github.actor }}"
}
EOF
- name: Upload deployment record
uses: actions/upload-artifact@v4
with:
name: deployment-record-mainnet-${{ github.sha }}
path: deployment-records/
retention-days: 365
- name: Create GitHub release
uses: actions/github-script@v7
with:
script: |
const tag = `contract-mainnet-${context.sha.slice(0,8)}`;
await github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `refs/tags/${tag}`,
sha: context.sha
});
await github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: tag,
name: `Mainnet Deployment — ${new Date().toISOString().split('T')[0]}`,
body: [
'## Mainnet Contract Deployment',
`**Contract ID:** \`${{ steps.deploy.outputs.contract_id }}\``,
`**WASM hash:** \`${{ needs.pre-deploy.outputs.wasm_hash }}\``,
`**Commit:** \`${{ github.sha }}\``,
`**Explorer:** https://stellar.expert/explorer/mainnet/contract/${{ steps.deploy.outputs.contract_id }}`
].join('\n'),
prerelease: false
});
# ─── Job 4: Rollback (manual trigger only) ───────────────────────────────────
rollback:
name: Rollback Contract
runs-on: ubuntu-latest
if: |
github.event_name == 'workflow_dispatch' &&
github.event.inputs.rollback_artifact != ''
environment:
name: ${{ github.event.inputs.network == 'mainnet' && 'production' || 'testnet' }}
steps:
- uses: actions/checkout@v4
- name: Install Stellar CLI
run: |
curl -sSL https://github.com/stellar/stellar-cli/releases/download/v22.7.1/stellar-cli-22.7.1-x86_64-unknown-linux-gnu.tar.gz \
| tar -xz -C /usr/local/bin stellar
- name: Execute rollback
run: bash scripts/rollback.sh
env:
STELLAR_NETWORK: ${{ github.event.inputs.network }}
STELLAR_RPC_URL: ${{ github.event.inputs.network == 'mainnet' && 'https://soroban-rpc.mainnet.stellar.gateway.fm' || 'https://soroban-testnet.stellar.org' }}
ROLLBACK_ARTIFACT_RUN_ID: ${{ github.event.inputs.rollback_artifact }}
DEPLOYER_SECRET: ${{ github.event.inputs.network == 'mainnet' && secrets.MAINNET_DEPLOYER_SECRET || secrets.TESTNET_DEPLOYER_SECRET }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}