Comprehensive guide for deploying Vesper Phase 1 to Stacks Testnet.
Phase 1: Smart contract deployment and batch automation verification
Target: Stacks Testnet (fully featured development network)
Contract: vesper-core (stream creation, withdrawal, top-up, cancel)
Frontend: Vesper App on Vercel (testnet mode)
Timeline: 2-4 hours for full deployment and verification
Local Development
↓
Smart Contract (vesper-core.clar)
├─ Create stream (14,000 µSTX cost to test)
├─ Withdraw from stream (50 µSTX per tx)
├─ Top-up stream (50 µSTX per tx)
└─ Cancel stream (50 µSTX per tx)
↓
Stacks Testnet
├─ Deploy smart contract
├─ Record contract address
└─ Update GitHub Secrets
↓
Daily Batch Automation
├─ Execute 14 transactions/day
├─ Test sweep-back recovery
└─ Verify all functions work
↓
Frontend Deployment
└─ Vesper App on Vercel (testnet config)
- Node.js 22 LTS (not 20)
- npm 11+
- Clarinet SDK 3.6.0+
- Git (for version control)
- curl (for API testing)
- GitHub account with access to Vesper repository
- Stacks Testnet wallet with STX for deployment fees
- Vercel account for frontend deployment (for Phase 1.17.3)
- Hiro API (stacks.co) - public, rate-limited
- Stacks Testnet node or API endpoint
- GitHub Actions secrets configured (see docs/SECRETS_SETUP.md)
# In your local development environment
cd scripts
# Generate fresh deployer wallet for testnet
npx ts-node -e "
import { generateWallets } from './batch-transactions.js';
const wallet = generateWallets(1)[0];
console.log('Testnet Deployer Wallet:');
console.log('Address:', wallet.address);
console.log('Private Key:', wallet.privateKey);
"Output Example:
Testnet Deployer Wallet:
Address: ST123ABCDEFGHIJKLMNOPQRSTUVWXYZ
Private Key: abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789
# Request 500 STX (500,000,000 µSTX) from testnet faucet
DEPLOYER_ADDRESS="ST123ABCDEFGHIJKLMNOPQRSTUVWXYZ"
curl -X POST https://api.testnet.hiro.so/extended/v1/faucets/stx \
-H "Content-Type: application/json" \
-d "{\"address\":\"$DEPLOYER_ADDRESS\"}"Response:
{
"success": true,
"txid": "0x..."
}Wait 30 seconds for transaction to confirm:
# Check balance
curl https://api.testnet.hiro.so/extended/v1/address/$DEPLOYER_ADDRESS/balances | jqAdd testnet secrets to GitHub (see docs/SECRETS_SETUP.md for full details):
- Go to Settings > Secrets and variables > Actions
- Add each secret:
| Name | Value | Type |
|---|---|---|
DEPLOYER_PRIVATE_KEY_TESTNET |
From Step 1.1 | Secret |
DEPLOYER_ADDRESS |
From Step 1.1 | Secret |
VESPER_CORE_ADDRESS_TESTNET |
Will update in Step 2 | Secret |
# Verify secrets via CLI
gh secret listcd /path/to/vesper
# Run pre-flight deployment checks
bash scripts/deploy-testnet.shExpected Output:
✓ Contract validation passed
✓ Deployment manifest created
✓ Pre-deployment validation complete
# Initialize deployment through Clarinet
clarinet deployments create testnet
# Follow prompts:
# - Network: testnet
# - Private Key: [Paste DEPLOYER_PRIVATE_KEY_TESTNET from Step 1.1]
# - Confirm deployment to testnetResult: Transaction broadcasted to testnet
# Poll for confirmation (takes ~15-30 min on testnet)
TX_ID="0x..." # From deployment output
for i in {1..60}; do
STATUS=$(curl -s https://api.testnet.hiro.so/extended/v1/tx/$TX_ID | jq -r '.tx_status')
if [ "$STATUS" = "success" ]; then
echo "✓ Contract deployed successfully"
break
elif [ "$STATUS" = "abort_by_response" ]; then
echo "✗ Deployment failed"
exit 1
fi
echo " Waiting for confirmation... ($i/60) [Status: $STATUS]"
sleep 30
doneOnce deployed, extract contract address:
TX_ID="0x..."
CONTRACT_INFO=$(curl -s https://api.testnet.hiro.so/extended/v1/tx/$TX_ID)
CONTRACT_ADDRESS=$(echo $CONTRACT_INFO | jq -r '.contract_id')
echo "Contract deployed at: $CONTRACT_ADDRESS"
# Output: ST123ABCDEFGHIJKLMNOPQRSTUVWXYZ.vesper-core# Update GitHub secret with deployed contract address
gh secret set VESPER_CORE_ADDRESS_TESTNET --body "ST123ABCDEFGHIJKLMNOPQRSTUVWXYZ.vesper-core"- Go to Testnet Stacks Explorer
- Search for contract address:
ST123ABCDEFGHIJKLMNOPQRSTUVWXYZ.vesper-core - Verify contract code matches
contracts/vesper-core.clar - Confirm functions are available:
create-streamwithdraw-from-streamtop-up-streamcancel-stream
# Trigger batch script on testnet via manual dispatch
gh workflow run daily-batch.yml -f network=testnet
# Wait for execution and verify results
# Check Actions tab for batch-logs artifactsExpected Results:
- All 14 transactions succeed
- Sweep-back recovers funds
- No errors in logs
cd /path/to/vesper
# Build with testnet configuration
VITE_NETWORK=testnet npm run build# Install Vercel CLI
npm install -g vercel
# Initialize deployment (if not already done)
cd frontend
vercelIn Vercel dashboard or CLI:
# Set testnet environment variables
vercel env add VITE_NETWORK testnet
vercel env add VITE_CONTRACT_ADDRESS "ST123ABCDEFGHIJKLMNOPQRSTUVWXYZ.vesper-core"# Deploy frontend to Vercel
vercel deploy --prod --env VITE_NETWORK=testnet
# Result: https://vesper-app.vercel.app (or custom domain)Before considering Phase 1 complete:
- Smart contract deployed to testnet
- Contract address recorded in GitHub Secrets
- Daily batch script runs successfully
- All 14 batch transactions execute
- Sweep-back recovery works
- Gas costs tracked in logs
- Frontend deployed to Vercel
- Frontend connects to testnet
- Wallet connection works in frontend
- Batch logs show all metrics
- Documentation updated with addresses
# Test contract read via API
curl https://api.testnet.hiro.so/extended/v1/contract/ST...vesper-core | jq
# Test batch script locally
VITE_NETWORK=testnet \
DEPLOYER_PRIVATE_KEY_TESTNET="..." \
DEPLOYER_ADDRESS="ST..." \
VESPER_CORE_ADDRESS_TESTNET="ST...vesper-core" \
npm run batch:testnet
# Check frontend deployment
curl -I https://vesper-app.vercel.app
# Verify batch logs uploaded
gh api repos/{owner}/{repo}/actions/artifacts --jq '.artifacts | .[] | select(.name | contains("batch-logs"))'Problem: "Invalid contract syntax" or deployment rejected
Solution:
- Verify contract compiles locally:
npm run test - Check contract has no syntax errors:
clarinet check - Ensure all dependencies are deployed first
- Try with lower confirmation requirement
Problem: "Connection refused" or timeout
Solution:
- Check Stacks status page: https://www.stacks.co/
- Verify testnet is operational and synced
- Try alternative Hiro endpoint if available
- Wait 10 minutes and retry
Problem: "Account balance too low" during deployment
Solution:
- Request more STX from faucet (can request multiple times)
- Wait for previous requests to confirm
- Check balance:
curl https://api.testnet.hiro.so/extended/v1/address/$DEPLOYER_ADDRESS/balances
Problem: Batch script works but fails when connecting to deployed contract
Solution:
- Verify contract address matches in secrets
- Ensure contract functions are identical to test expectations
- Check contract is actually deployed (search in explorer)
- Review batch logs for specific error messages
After successful deployment:
- Monitor daily batches: Check GitHub Actions every 24 hours
- Review logs: Download and analyze batch JSON logs
- Track metrics: Monitor gas costs, transaction success rates
- Test frontend: Interact with deployed testnet app
- Verify recovery: Check that sweep-back consistently recovers funds
After successful Phase 1 testnet deployment:
- Mainnet contract deployment
- Mainnet batch automation
- Production frontend deployment
- Mainnet monitoring and alerting
- Setup Issues: SECRETS_SETUP.md
- Daily Operations: DAILY_AUTOMATION.md
- Batch Script: scripts/batch-transactions.ts
- Smart Contract: contracts/vesper-core.clar
- Stacks Docs: https://docs.stacks.co/
- Testnet Explorer: https://testnet-explorer.alexgo.io/
Phase 1 Timeline: 2-4 hours
Phase 2 Timeline: 1-2 days (mainnet deployment)
Full Production: End of Phase 2