First Flash Loan Protocol on Bitcoin Layer 2
Last Updated: December 7, 2025 - Testnet Launch
FlashStack is now live on Stacks testnet with 100% test success rate!
Testnet Deployment:
- Deployer Address:
ST2X1GBHA2WJXREWP231EEQXZ1GDYZEEXYRAD1PA8 - Network: Stacks Testnet
- Status: Ready for audit (code works, needs security review)
- Test Results: 8/8 Passed (27M sBTC volume)
GitHub Repository:
git clone https://github.com/mattglory/flashstack
cd flashstack- Overview
- Getting Started
- Core Contracts
- Integration Guide
- Receiver Contracts
- Testing
- Deployment
- API Reference
- Examples
- Best Practices
- Troubleshooting
- Resources
FlashStack enables uncollateralized flash loans on Stacks (Bitcoin Layer 2). Borrow millions of sBTC for a single transaction with no collateral required.
Key Features:
- ✅ Zero collateral required
- ✅ Atomic execution guarantee
- ✅ 0.05% competitive fees
- ✅ Zero-inflation guarantee
- ✅ 8 production-ready receivers
- ✅ 100% test success rate
1. BORROW → 2. EXECUTE → 3. REPAY
↓ ↓ ↓
Mint sBTC Your Logic Burn sBTC
↓ ↓ ↓
If repayment fails → ENTIRE TRANSACTION REVERTS
All or nothing:
- Success = profit kept, loan repaid, zero inflation
- Failure = transaction reverts, no tokens created
Required:
- Clarity smart contract knowledge
- Clarinet installed (
brew install clarinet) - Basic understanding of flash loans
- Stacks wallet (testnet STX for deployment)
Recommended:
- Git installed
- Code editor (VS Code + Clarity extension)
- Stacks Explorer access
- Discord/X for support
# Clone repository
git clone https://github.com/mattglory/flashstack
cd flashstack
# Install dependencies (if any)
clarinet install
# Run tests
clarinet test
# Start console for local testing
clarinet consoleflashstack/
├── contracts/
│ ├── flashstack-core.clar # Main protocol
│ ├── sbtc-token.clar # Flash-mintable token
│ ├── flash-receiver-trait.clar # Interface
│ ├── test-receiver.clar # Simple example
│ ├── example-arbitrage-receiver.clar
│ ├── liquidation-receiver.clar
│ ├── leverage-loop-receiver.clar
│ ├── yield-optimization-receiver.clar
│ ├── collateral-swap-receiver.clar
│ ├── dex-aggregator-receiver.clar
│ └── multidex-arbitrage-receiver.clar
├── tests/
│ └── flashstack_test.ts # Comprehensive tests
├── settings/
│ ├── Devnet.toml
│ └── Testnet.toml
├── docs/
│ ├── TECHNICAL_SPEC.md
│ ├── INTEGRATION_GUIDE.md
│ ├── API_REFERENCE.md
│ ├── TESTNET_SUCCESS.md
│ └── RECEIVER_TESTING_GUIDE.md
└── README.md
Main protocol contract orchestrating flash loans.
Key Functions:
;; Execute a flash loan
(define-public (flash-mint (amount uint) (receiver <flash-receiver-trait>))
(response (tuple ...) uint))
;; Get current protocol statistics
(define-read-only (get-stats)
(response (tuple ...) uint))
;; Calculate fee for amount
(define-read-only (calculate-fee (amount uint))
uint)
;; Check if protocol is paused
(define-read-only (is-paused)
bool)Admin Functions:
;; Set fee (owner only)
(define-public (set-fee (new-fee-bp uint))
(response bool uint))
;; Pause protocol (owner only)
(define-public (pause)
(response bool uint))
;; Unpause protocol (owner only)
(define-public (unpause)
(response bool uint))Flash-mintable synthetic Bitcoin token (SIP-010 compliant).
Key Functions:
;; Mint tokens (flash minter only)
(define-public (mint (amount uint) (recipient principal))
(response bool uint))
;; Burn tokens (anyone with balance)
(define-public (burn (amount uint) (sender principal))
(response bool uint))
;; Standard SIP-010 transfer
(define-public (transfer (amount uint) (sender principal)
(recipient principal) (memo (optional (buff 34))))
(response bool uint))
;; Get total supply
(define-read-only (get-total-supply)
(response uint uint))Admin Functions:
;; Set flash minter authorization (owner only)
(define-public (set-flash-minter (minter principal))
(response bool uint))Interface all receiver contracts must implement.
(define-trait flash-receiver-trait
(
;; Execute flash loan logic
;; @param amount - Principal borrowed
;; @param fee - Fee charged (0.05% = 5 basis points)
;; @returns (ok true) if successful, (err ...) if failed
(execute-flash-loan (uint uint) (response bool uint))
)
)(impl-trait .flash-receiver-trait.flash-receiver-trait)(define-public (execute-flash-loan (amount uint) (fee uint))
(let (
(total-repayment (+ amount fee))
(profit u0) ;; Will be calculated
)
;; 1. VALIDATE INPUTS
(asserts! (> amount u0) ERR-ZERO-AMOUNT)
;; 2. YOUR CUSTOM LOGIC HERE
;; Examples:
;; - Arbitrage across DEXs
;; - Liquidate positions
;; - Build leveraged position
;; - Optimize yield
;; - Anything else!
;; Example: Simple arbitrage
(let (
(tokens-bought (try! (buy-on-dex-1 amount)))
(sbtc-received (try! (sell-on-dex-2 tokens-bought)))
)
(set profit (- sbtc-received total-repayment))
;; 3. VALIDATE PROFIT
(asserts! (> profit u0) ERR-UNPROFITABLE)
;; 4. TRANSFER REPAYMENT TO FLASHSTACK-CORE
(try! (contract-call? .sbtc-token transfer
total-repayment tx-sender .flashstack-core none))
;; 5. RETURN SUCCESS
(ok true)
)
)
)From your contract:
(define-public (execute-arbitrage)
(contract-call? .flashstack-core flash-mint
u1000000 ;; Borrow 1M sBTC
(as-contract tx-sender)) ;; Your receiver contract
)From Clarinet console:
(contract-call? .flashstack-core flash-mint
u1000000
.your-receiver)From Stacks Explorer (testnet):
1. Go to: explorer.hiro.so/sandbox
2. Navigate to: flashstack-core contract
3. Call: flash-mint function
4. Provide: amount and receiver address
# Start Clarinet console
clarinet console
# Test your receiver
(contract-call? .flashstack-core flash-mint
u1000000 .your-receiver)
# Check supply returned to 0
(contract-call? .sbtc-token get-total-supply)
;; Should return (ok u0)
# Check statistics updated
(contract-call? .flashstack-core get-stats)FlashStack includes 8 production-ready receiver examples.
Purpose: Simple pass-through for testing Complexity: ⭐ Beginner Use Case: Verify flash loan mechanics
(define-public (execute-flash-loan (amount uint) (fee uint))
(let ((total-repayment (+ amount fee)))
(try! (contract-call? .sbtc-token transfer
total-repayment tx-sender .flashstack-core none))
(ok true)))Purpose: DEX arbitrage Complexity: ⭐⭐ Intermediate Use Case: Profit from price differences
Key Functions:
execute-flash-loan: Main arbitrage logiccalculate-expected-profit: Profitability checkget-dex-prices: Price feed integration
Purpose: Liquidate undercollateralized positions Complexity: ⭐⭐⭐ Advanced Use Case: Lending protocol liquidations
Key Functions:
execute-flash-loan: Liquidation orchestrationcalculate-liquidation-profit: Profit analysischeck-position-health: Position monitoring
Purpose: Build leveraged positions
Complexity: ⭐⭐⭐ Advanced
Use Case: One-transaction leverage
Key Functions:
execute-flash-loan: Leverage buildingcalculate-max-leverage: Safety limitsoptimize-loop-iterations: Gas efficiency
Purpose: Rebalance across protocols Complexity: ⭐⭐⭐ Advanced Use Case: Yield farming optimization
Key Functions:
execute-flash-loan: Rebalancing logiccompare-yields: Protocol comparisoncalculate-optimal-allocation: Position sizing
Purpose: Change collateral type Complexity: ⭐⭐ Intermediate Use Case: Collateral management
Key Functions:
execute-flash-loan: Swap orchestrationcalculate-swap-amounts: Size calculationvalidate-collateral-ratios: Safety checks
Purpose: Multi-DEX routing Complexity: ⭐⭐⭐⭐ Expert Use Case: Large trade optimization
Key Functions:
execute-flash-loan: Multi-venue executionoptimize-routing: Path findingsplit-order: Order splitting logic
Purpose: Complex multi-step arbitrage Complexity: ⭐⭐⭐⭐ Expert Use Case: Triangular/circular arbitrage
Key Functions:
execute-flash-loan: Multi-hop tradingfind-profitable-paths: Opportunity detectionexecute-trades: Trade execution
# Run all tests
clarinet test
# Run specific test
clarinet test --filter flash_loan_basic
# Run with coverage
clarinet test --coverageTest Categories:
- Core functionality (mint, burn, transfer)
- Flash loan execution
- Fee calculations
- Access controls
- Error handling
- Edge cases
- Integration tests
Deployment Address:
ST2X1GBHA2WJXREWP231EEQXZ1GDYZEEXYRAD1PA8
Test Procedure:
- Deploy your receiver to testnet
- Get testnet STX from faucet
- Call flash-mint via Explorer
- Verify transaction success
- Check supply returned to 0
- Monitor statistics
Testnet Explorer:
https://explorer.hiro.so/sandbox/contract-call/ST2X1GBHA2WJXREWP231EEQXZ1GDYZEEXYRAD1PA8.flashstack-core/flash-mint?chain=testnet
After each test:
- Transaction succeeded (ok ...)
- Mint event emitted
- Transfer event emitted
- Burn event emitted
- Supply returned to 0
- Statistics incremented
- Fee calculated correctly
Already Deployed:
All FlashStack contracts are live on testnet at:
ST2X1GBHA2WJXREWP231EEQXZ1GDYZEEXYRAD1PA8
Deploy Your Receiver:
# Generate deployment plan
clarinet deployments generate --testnet --medium-cost
# Review plan
cat deployments/default.testnet-plan.yaml
# Apply deployment
clarinet deployments apply -p deployments/default.testnet-plan.yamlStatus: Planned Q1 2026 (post-audit)
Requirements:
- Security audit completed
- Community feedback integrated
- Sufficient mainnet STX for fees
- Deployment checklist completed
Process:
- Final security review
- Deployment plan generation
- Community announcement
- Staged rollout
- Monitoring and support
(define-public (flash-mint
(amount uint)
(receiver <flash-receiver-trait>))
(response
(tuple
(amount uint)
(borrower principal)
(fee uint)
(flash-mint-id uint)
(total-minted uint))
uint))Parameters:
amount: Principal to borrow (in micro-sBTC)receiver: Contract implementing flash-receiver-trait
Returns:
- Success:
(ok {amount, borrower, fee, flash-mint-id, total-minted}) - Failure:
(err u<error-code>)
Errors:
u401: ERR-PAUSED (protocol paused)u402: ERR-INVALID-RECEIVER (receiver failed)u403: ERR-MINT-FAILED (token mint failed)u404: ERR-BURN-FAILED (token burn failed)
(define-read-only (get-stats)
(response
(tuple
(current-fee-bp uint)
(paused bool)
(total-fees-collected uint)
(total-flash-mints uint)
(total-volume uint))
uint))Returns: Protocol statistics
(define-read-only (calculate-fee (amount uint))
uint)Parameters:
amount: Loan amount
Returns: Fee in micro-sBTC (amount × fee-bp ÷ 10000)
(define-public (mint (amount uint) (recipient principal))
(response bool uint))Authorization: Flash minter only
(define-public (burn (amount uint) (sender principal))
(response bool uint))Authorization: Anyone with balance
(define-public (transfer
(amount uint)
(sender principal)
(recipient principal)
(memo (optional (buff 34))))
(response bool uint))Standard SIP-010 transfer
(define-public (execute-flash-loan (amount uint) (fee uint))
(let (
(total-repayment (+ amount fee))
;; Buy on DEX 1 (cheaper)
(tokens (try! (contract-call? .dex-1 swap-exact-tokens-for-tokens
amount .sbtc-token .target-token u0)))
;; Sell on DEX 2 (expensive)
(sbtc (try! (contract-call? .dex-2 swap-exact-tokens-for-tokens
tokens .target-token .sbtc-token u0)))
)
;; Ensure profitable
(asserts! (>= sbtc total-repayment) ERR-UNPROFITABLE)
;; Repay loan
(try! (contract-call? .sbtc-token transfer
total-repayment tx-sender .flashstack-core none))
(ok true)
)
)(define-public (execute-flash-loan (amount uint) (fee uint))
(let (
(total-repayment (+ amount fee))
;; Liquidate position
(collateral (try! (contract-call? .lending-protocol liquidate
.borrower-address amount)))
;; Swap collateral for sBTC
(sbtc (try! (contract-call? .dex swap-exact-tokens-for-tokens
collateral .collateral-token .sbtc-token u0)))
)
;; Ensure enough to repay
(asserts! (>= sbtc total-repayment) ERR-INSUFFICIENT-COLLATERAL)
;; Repay loan
(try! (contract-call? .sbtc-token transfer
total-repayment tx-sender .flashstack-core none))
(ok true)
)
)(define-public (execute-flash-loan (amount uint) (fee uint))
(let (
(total-repayment (+ amount fee))
(user-capital (var-get initial-capital))
(total-collateral (+ user-capital amount))
)
;; Deposit all as collateral
(try! (contract-call? .lending-protocol deposit total-collateral))
;; Borrow against it
(let ((borrowed (try! (contract-call? .lending-protocol borrow
(calculate-borrow-amount total-collateral)))))
;; Ensure can repay flash loan
(asserts! (>= borrowed total-repayment) ERR-INSUFFICIENT-BORROW)
;; Repay flash loan
(try! (contract-call? .sbtc-token transfer
total-repayment tx-sender .flashstack-core none))
(ok true)
)
)
)1. Always validate inputs:
(asserts! (> amount u0) ERR-ZERO-AMOUNT)
(asserts! (<= amount MAX-LOAN) ERR-EXCEEDS-MAX)2. Check profitability before execution:
(define-read-only (is-profitable (amount uint))
(let ((expected-profit (calculate-profit amount)))
(> expected-profit (calculate-fee amount))))3. Use read-only functions for calculations:
(define-read-only (calculate-expected-output (input uint))
;; Pure calculation, no state changes
)4. Emit detailed events:
(print {
event: "flash-loan-executed",
amount: amount,
fee: fee,
profit: profit,
strategy: "arbitrage"
})1. Minimize external calls:
;; Bad: Multiple calls
(contract-call? .contract-a get-price)
(contract-call? .contract-b get-price)
(contract-call? .contract-c get-price)
;; Good: Batch call if possible
(contract-call? .aggregator get-all-prices)2. Use let bindings efficiently:
;; Avoid recalculating
(let ((total (+ amount fee)))
;; Use 'total' multiple times
)3. Early exit on failures:
;; Check cheapest conditions first
(asserts! (> amount MIN-AMOUNT) ERR-TOO-SMALL)
(asserts! (is-profitable amount) ERR-UNPROFITABLE)
;; Then expensive operationsDefine clear error codes:
(define-constant ERR-ZERO-AMOUNT (err u100))
(define-constant ERR-UNPROFITABLE (err u101))
(define-constant ERR-INSUFFICIENT-LIQUIDITY (err u102))
(define-constant ERR-SLIPPAGE-TOO-HIGH (err u103))Provide context in errors:
(asserts! (>= output min-output)
(err (tuple (code u103) (expected min-output) (actual output))))Cause: Flash minter not set or calling from wrong address Solution:
;; Ensure flashstack-core is authorized
(contract-call? .sbtc-token set-flash-minter .flashstack-core)Cause: Not enough tokens to repay Solution: Check your profit calculation includes fee
(let ((profit (- output (+ amount fee))))
(asserts! (> profit u0) ERR-UNPROFITABLE))Cause: Burn amount doesn't match mint amount Solution: Always burn exact total-repayment
(define-constant total-repayment (+ amount fee))
(try! (contract-call? .sbtc-token burn total-repayment ...))Cause: Too many operations in flash loan Solution: Optimize or split strategy
;; Reduce external calls
;; Use batch operations
;; Simplify logic- Implement flash-receiver-trait correctly
- Calculate fee: (amount × 5) ÷ 10000
- Transfer exact total-repayment
- Handle all error cases
- Test locally first
- Check gas costs
- Verify profitability
Resources:
- GitHub Issues: github.com/mattglory/flashstack/issues
- Twitter: @FlashStackBTC
- Stacks Discord: #flashstack channel
- Documentation: github.com/mattglory/flashstack/docs
When asking for help, provide:
- Contract code (relevant sections)
- Error message / transaction ID
- Expected vs. actual behavior
- Testing environment (local/testnet)
- Clarinet version
GitHub:
- Repository: github.com/mattglory/flashstack
- Issues: github.com/mattglory/flashstack/issues
- Discussions: github.com/mattglory/flashstack/discussions
Social:
- Twitter: @FlashStackBTC
- Developer: @mattglory
Documentation:
- Technical Spec: /docs/TECHNICAL_SPEC.md
- Integration Guide: /docs/INTEGRATION_GUIDE.md
- API Reference: /docs/API_REFERENCE.md
- Testing Guide: /docs/RECEIVER_TESTING_GUIDE.md
Deployed Contracts:
Deployer: ST2X1GBHA2WJXREWP231EEQXZ1GDYZEEXYRAD1PA8
Core:
- flashstack-core
- sbtc-token
- flash-receiver-trait
Receivers:
- test-receiver
- example-arbitrage-receiver
- liquidation-receiver
- leverage-loop-receiver
- yield-optimization-receiver
- collateral-swap-receiver
- dex-aggregator-receiver
- multidex-arbitrage-receiver
Explorer Links:
- Testnet Explorer: explorer.hiro.so?chain=testnet
- Sandbox: explorer.hiro.so/sandbox
- Contract Calls: explorer.hiro.so/sandbox/contract-call
Testnet Tools:
- Faucet: explorer.hiro.so/sandbox/faucet
- STX Faucet: Get test STX for deployment
- sBTC Faucet: [Coming soon]
Clarity:
- Book: book.clarity-lang.org
- Tutorial: docs.stacks.co/clarity
- Examples: github.com/hirosystems/clarity-examples
Flash Loans:
- Aave Docs: docs.aave.com/developers/guides/flash-loans
- dYdX Docs: dydx.exchange/developers
- Concepts: ethereum.org/en/defi/#flash-loans
Stacks:
- Docs: docs.stacks.co
- Discord: discord.gg/stacks
- Forum: forum.stacks.org
Date: December 7, 2025
Success Rate: 8/8 (100%)
Total Volume: 27,000,000 sBTC
Total Fees: 15,250 sBTC
Individual Tests:
- test-receiver: 1M sBTC ✅
- example-arbitrage: 3M sBTC ✅
- liquidation: 5M sBTC ✅
- leverage-loop: 2M sBTC ✅
- yield-optimization: 3.5M sBTC ✅
- collateral-swap: 2.5M sBTC ✅
- dex-aggregator: 6M sBTC ✅ (LARGEST)
- multidex-arbitrage: 4M sBTC ✅ (FINAL)
Verification:
- Supply: (ok u0) ✅
- Statistics: All correct ✅
- Events: All present ✅
- Fees: Correctly calculated ✅
Ready to build? Start with test-receiver and work your way up!
Questions? Reach out on Twitter: @FlashStackBTC
Documentation maintained by @mattglory
Last updated: December 7, 2025
Version: 1.0.0-testnet