Toolkit Ecosystem Development

deployment

by Superteam Brazil · solanabr/solana-ai-kit · Agent view ↗

Devnet-first deployment flow with mainnet confirmation gates.

Ecosystem skill — independently developed and maintained by Superteam Brazil, not the Solana Foundation. No security review is performed; evaluate before use.

One command for Claude Code, Cursor, Codex, Windsurf and other agents — installs from the upstream repo (current HEAD; it ships 6 skills — pick deployment when prompted).

$npx skills add solanabr/solana-ai-kit

Skill contents

Deployment Workflows

Deployment Strategy Overview

EnvironmentPurposeCommitmentUpgrades
localnetDevelopmentprocessedFrequent, no restrictions
devnetTestingconfirmedFrequent, test multisig
testnetStagingconfirmedControlled, production-like
mainnetProductionfinalizedRare, full security review

Pre-Deployment Checklist

Code Quality

  • All tests passing (unit, integration, fuzz)
  • Security audit completed (for mainnet)
  • Code review approved
  • No unwrap() or expect() in program code
  • All arithmetic uses checked operations

Build Verification

  • Verifiable build successful
  • Binary hash matches expected
  • IDL generated and committed
  • Client SDK generated and tested

Security Review

  • All accounts validated
  • CPI targets hardcoded
  • PDA bumps stored
  • Accounts reloaded after CPIs
  • Reentrancy considered

Documentation

  • CHANGELOG updated
  • Migration guide if breaking changes
  • User-facing documentation updated

Devnet Deployment

First Deployment

# 1. Build with verifiable flag
anchor build --verifiable

# 2. Get program keypair
solana-keygen new -o target/deploy/my_program-keypair.json

# 3. Airdrop devnet SOL
solana airdrop 2 --url devnet

# 4. Deploy to devnet
anchor deploy --provider.cluster devnet

# 5. Verify deployment
solana program show <PROGRAM_ID> --url devnet

Upgrade Deployment

# 1. Build new version
anchor build --verifiable

# 2. Verify buffer before upgrade
solana program write-buffer target/deploy/my_program.so --url devnet
solana program show <BUFFER_ADDRESS> --url devnet

# 3. Deploy upgrade
anchor upgrade target/deploy/my_program.so \
    --program-id <PROGRAM_ID> \
    --provider.cluster devnet

# 4. Close old buffers to reclaim SOL
solana program close --buffers --url devnet

IDL Update

# Update IDL on-chain (required for explorer parsing)
anchor idl upgrade --filepath target/idl/my_program.json \
    --provider.cluster devnet \
    <PROGRAM_ID>

Mainnet Deployment

Pre-Mainnet Verification

# 1. Full test suite
cargo test --all

# 2. Fuzz testing (critical paths)
trident fuzz run fuzz_0 --iterations 50000

# 3. Build verification
anchor build --verifiable
anchor verify <PROGRAM_ID> --provider.cluster devnet

# 4. Audit tool scan
soteria -analyzeAll .

Mainnet First Deploy

# 1. Ensure sufficient SOL (deployment costs ~2-5 SOL depending on program size)
solana balance --url mainnet

# 2. Build verifiable
anchor build --verifiable

# 3. Deploy with confirmation prompts
anchor deploy --provider.cluster mainnet

# 4. Immediately verify on-chain
anchor verify <PROGRAM_ID> --provider.cluster mainnet

# 5. Publish IDL
anchor idl init --filepath target/idl/my_program.json \
    --provider.cluster mainnet \
    <PROGRAM_ID>

Mainnet Upgrade (With Multisig)

For production programs, use a multisig upgrade authority:

# 1. Write new buffer (anyone can do this)
solana program write-buffer target/deploy/my_program.so \
    --url mainnet \
    --buffer-authority <MULTISIG_PDA>

# 2. Verify buffer contents
solana program dump <BUFFER_ADDRESS> buffer_dump.so --url mainnet
diff <(xxd target/deploy/my_program.so) <(xxd buffer_dump.so)

# 3. Create upgrade proposal via multisig UI (e.g., Squads)
# Members review and approve

# 4. Execute upgrade after threshold reached
# (Handled by multisig program)

# 5. Verify post-upgrade
anchor verify <PROGRAM_ID> --provider.cluster mainnet

Multisig Setup (Squads v4)

Creating a Squad for Program Authority

import { Squads } from "@sqds/multisig";

async function createProgramSquad() {
  const squads = new Squads({ connection, wallet });

  // Create multisig with 2-of-3 threshold
  const multisigPda = await squads.createMultisig({
    threshold: 2,
    members: [
      { pubkey: member1.publicKey, permissions: { vote: true, execute: true } },
      { pubkey: member2.publicKey, permissions: { vote: true, execute: true } },
      { pubkey: member3.publicKey, permissions: { vote: true, execute: false } },
    ],
  });

  console.log("Multisig created:", multisigPda.toString());
  return multisigPda;
}

Transferring Upgrade Authority to Multisig

# Transfer program upgrade authority to multisig
solana program set-upgrade-authority <PROGRAM_ID> \
    --new-upgrade-authority <MULTISIG_PDA> \
    --url mainnet

Creating Upgrade Proposals

async function proposeUpgrade(
  squads: Squads,
  multisigPda: PublicKey,
  programId: PublicKey,
  bufferAddress: PublicKey
) {
  const transaction = await squads.createTransaction({
    multisig: multisigPda,
    instructions: [
      SystemProgram.createUpgradeInstruction({
        programId,
        bufferAddress,
        upgradeAuthority: multisigPda,
        spillAccount: treasury,
      }),
    ],
  });

  console.log("Upgrade proposal created:", transaction.toString());
}

Upgrade Authority Staging

Stage the path to immutability rather than freezing at launch:

  1. Launch → ~3 months — keep upgrade authority on a secured deployer key (hardware wallet). Bugs surface early; you need the ability to ship fixes fast.
  2. ~3 months post-launch — transfer authority to the Squads multisig (above). Removes single-key risk once the program is stable.
  3. Post-audit, battle-tested — freeze: solana program set-upgrade-authority <PROGRAM_ID> --final. Irreversible and removes any rollback path — only after extensive mainnet history and a completed audit.

CI/CD Pipeline

GitHub Actions Workflow

name: Solana Program CI/CD

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  SOLANA_VERSION: "2.1.0"
  ANCHOR_VERSION: "0.31.1"

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Solana
        uses: solana-labs/solana-actions/setup@v1
        with:
          solana-version: ${{ env.SOLANA_VERSION }}

      - name: Setup Anchor
        run: |
          cargo install --git https://github.com/coral-xyz/anchor anchor-cli --tag v${{ env.ANCHOR_VERSION }}

      - name: Install dependencies
        run: yarn install

      - name: Build
        run: anchor build --verifiable

      - name: Test
        run: anchor test

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: program-artifacts
          path: |
            target/deploy/*.so
            target/idl/*.json

  deploy-devnet:
    needs: test
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    environment: devnet
    steps:
      - uses: actions/checkout@v4

      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          name: program-artifacts

      - name: Setup Solana
        uses: solana-labs/solana-actions/setup@v1

      - name: Configure keypair
        run: |
          echo "${{ secrets.DEVNET_DEPLOYER_KEYPAIR }}" > deployer.json
          solana config set --keypair deployer.json --url devnet

      - name: Deploy to devnet
        run: |
          anchor deploy --provider.cluster devnet

      - name: Verify deployment
        run: |
          anchor verify ${{ vars.PROGRAM_ID }} --provider.cluster devnet

  deploy-mainnet:
    needs: test
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    runs-on: ubuntu-latest
    environment: mainnet
    steps:
      - uses: actions/checkout@v4

      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          name: program-artifacts

      - name: Write buffer
        run: |
          # Only write buffer - manual multisig approval required
          echo "${{ secrets.MAINNET_BUFFER_KEYPAIR }}" > buffer.json
          solana program write-buffer target/deploy/my_program.so \
              --url mainnet \
              --keypair buffer.json

      - name: Output buffer address
        id: buffer
        run: echo "::set-output name=address::$(cat buffer-address.txt)"

      - name: Create PR comment
        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: `🚀 Buffer written to mainnet: \`${{ steps.buffer.outputs.address }}\`\n\nApprove upgrade via Squads multisig.`
            })

Rollback Procedures

Devnet Rollback

# Redeploy previous version
anchor deploy --provider.cluster devnet \
    --program-id <PROGRAM_ID> \
    target/deploy/my_program_v1.so

Mainnet Rollback

  1. Immediate: If caught quickly, create emergency multisig proposal for rollback
  2. Planned: Keep previous verified buffer, create upgrade proposal to previous version
  3. Emergency freeze: If program has freeze capability, pause operations while preparing rollback

Freeze Pattern (Program Design)

#[account]
pub struct GlobalState {
    pub authority: Pubkey,
    pub is_frozen: bool,  // Emergency stop
}

// In each instruction
pub fn some_instruction(ctx: Context<SomeInstruction>) -> Result<()> {
    require!(!ctx.accounts.global_state.is_frozen, ErrorCode::ProgramFrozen);
    // ... instruction logic
}

Environment Configuration

.env.development

SOLANA_RPC_URL=http://localhost:8899
SOLANA_WS_URL=ws://localhost:8900
PROGRAM_ID=<LOCAL_PROGRAM_ID>

.env.devnet

SOLANA_RPC_URL=https://api.devnet.solana.com
SOLANA_WS_URL=wss://api.devnet.solana.com
PROGRAM_ID=<DEVNET_PROGRAM_ID>

.env.mainnet

SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
SOLANA_WS_URL=wss://api.mainnet-beta.solana.com
PROGRAM_ID=<MAINNET_PROGRAM_ID>
# Consider premium RPC providers for production:
# - Helius
# - QuickNode
# - Triton

Deployment Cost Estimation

ActionApproximate Cost
Deploy small program (<100KB)~1.5 SOL
Deploy medium program (100-500KB)~3-5 SOL
Deploy large program (>500KB)~5-10 SOL
Upgrade (buffer write)Same as deploy
IDL init/upgrade~0.01 SOL
Close old buffersReturns ~90% of rent

Tip: Close unused buffers after upgrades to reclaim SOL:

solana program close --buffers --url mainnet

Post-Deployment Verification

On-Chain Verification

# Verify program binary matches source
anchor verify <PROGRAM_ID> --provider.cluster mainnet

# Check program authority
solana program show <PROGRAM_ID> --url mainnet

# Verify IDL
anchor idl fetch <PROGRAM_ID> --provider.cluster mainnet > fetched_idl.json
diff target/idl/my_program.json fetched_idl.json

Functional Verification

# Run smoke tests against deployed program
anchor test --skip-build --provider.cluster devnet

# Monitor logs for first transactions
solana logs <PROGRAM_ID> --url devnet

Best Practices Summary

  1. Always use verifiable builds for production deployments
  2. Use multisig for mainnet upgrade authority
  3. Test on devnet before mainnet
  4. Keep deployment keys secure (HSM or multisig)
  5. Document every deployment with version and hash
  6. Have a rollback plan before deploying
  7. Monitor post-deployment for anomalies
  8. Close old buffers to reclaim SOL