Development of Application on Stacks (Bitcoin L2)
Stacks solves specific problem: Bitcoin is most secure and decentralized blockchain, but has no smart contracts and no way to build DeFi/NFT/dApps on top of it. Most "Bitcoin DeFi" is actually built on Ethereum or Solana with BTC price only as reference. Stacks adds smart contract layer cryptographically tied to Bitcoin via Proof of Transfer (PoX) consensus — each Stacks block anchored to Bitcoin block, getting its finality.
Stacks Architecture: What Developer Should Understand
Proof of Transfer (PoX) and Nakamoto Release
Before Nakamoto Release (2024) Stacks had main problem: transaction finality depended on Bitcoin block, i.e., ~10 minutes. Unacceptable for most dApps.
Nakamoto Release changed this dramatically. Now Stacks produces fast blocks (~5 sec) within one Bitcoin block, yet finality still tied to Bitcoin through anchoring. Attack on Stacks history requires attack on Bitcoin — exactly what Bitcoin-native DeFi wants.
sBTC — mechanism for bridging BTC to Stacks. User deposits BTC in multisig wallet controlled by signer network, receives sBTC (1:1 peg) on Stacks. sBTC is not wrapped BTC under one company control, it's decentralized peg with threshold signature scheme of network Signers. For developer: sBTC is Stacks fungible token operable in Clarity contracts.
Clarity vs Solidity: Fundamental Differences
Clarity is smart contract language for Stacks. Not compiled — interpreted. This is principal design choice.
Decidability: programs in Clarity decidable — can statically determine all execution branches and gas cost. No recursion, no goto. This makes audit simpler and formal verification possible.
No reentrancy by design: Clarity doesn't allow external calls to change state after contract-call? if contract already in call stack. Classic reentrancy attack (DAO hack) impossible constructively.
Post-conditions: caller (not contract!) can set conditions on what happens with their assets. User can say: "accept this transaction only if from my wallet no more than X STX is debited." Contract can't bypass these conditions. This is protection from approvals exploit type.
;; Post-condition example (set in transaction, not in contract)
;; Stacks.js automatically adds on correct SDK usage
Development in Clarity: Practice
Basic Smart Contract: Fungible Token
;; sip-010-trait — fungible token standard on Stacks (like ERC-20)
(impl-trait 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait)
(define-fungible-token my-token u1000000000) ;; max supply
(define-constant contract-owner tx-sender)
(define-constant ERR_UNAUTHORIZED (err u100))
(define-constant ERR_INSUFFICIENT_BALANCE (err u101))
(define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34))))
(begin
(asserts! (is-eq tx-sender sender) ERR_UNAUTHORIZED)
(try! (ft-transfer? my-token amount sender recipient))
(match memo to-print (print to-print) 0x)
(ok true)
)
)
(define-read-only (get-balance (who principal))
(ok (ft-get-balance my-token who))
)
(define-read-only (get-total-supply)
(ok (ft-get-supply my-token))
)
Interacting with sBTC
sBTC implements SIP-010 trait, so working with it no different from any other fungible token:
;; sBTC contract address on mainnet
(define-constant SBTC_CONTRACT 'SM3VDXK3WZZSA84XXFKAFAF15SSKSY0NRY41R6Q5.sbtc-token)
(define-public (deposit-sbtc (amount uint))
(begin
;; Transfer sBTC from user to this contract
(try! (contract-call? SBTC_CONTRACT transfer
amount
tx-sender
(as-contract tx-sender)
none
))
;; Protocol logic...
(ok true)
)
)
Maps and State Management
;; Equivalent of mapping in Solidity
(define-map user-positions
{ user: principal }
{ deposited: uint, rewards-earned: uint, last-claim-block: uint }
)
(define-public (stake (amount uint))
(let (
(current-pos (default-to
{ deposited: u0, rewards-earned: u0, last-claim-block: block-height }
(map-get? user-positions { user: tx-sender })
))
)
(try! (contract-call? SBTC_CONTRACT transfer amount tx-sender (as-contract tx-sender) none))
(map-set user-positions
{ user: tx-sender }
{ deposited: (+ (get deposited current-pos) amount),
rewards-earned: (get rewards-earned current-pos),
last-claim-block: block-height }
)
(ok true)
)
)
Tooling and Development Environment
Clarinet — main development tool for Clarity (analog of Foundry for EVM):
# Project creation
clarinet new my-protocol
cd my-protocol
# Structure:
# contracts/ — .clar files
# tests/ — TypeScript tests via Vitest
# Clarinet.toml
# Run tests
clarinet test
# Local devnet
clarinet devnet start
Tests in TypeScript via Clarinet SDK:
import { describe, it, expect } from "vitest";
import { Cl } from "@stacks/transactions";
import { initSimnet } from "@hirosystems/clarinet-sdk";
const simnet = await initSimnet();
const accounts = simnet.getAccounts();
const deployer = accounts.get("deployer")!;
describe("my-token", () => {
it("should transfer tokens correctly", () => {
const { result } = simnet.callPublicFn(
"my-token",
"transfer",
[Cl.uint(100), Cl.principal(deployer), Cl.principal(accounts.get("wallet_1")!), Cl.none()],
deployer
);
expect(result).toBeOk(Cl.bool(true));
});
});
Stacks Explorer (explorer.stacks.co) — transaction browser. Hiro Platform — managed deployment and monitoring. Stacks.js — official TypeScript SDK for frontend:
import { openContractCall } from "@stacks/connect";
import { uintCV, standardPrincipalCV } from "@stacks/transactions";
await openContractCall({
contractAddress: "SP...",
contractName: "my-protocol",
functionName: "stake",
functionArgs: [uintCV(1000000)], // 1 sBTC = 100,000,000 satoshi
postConditions: [
// Protection: user not debiting more than 1 sBTC
makeStandardFungiblePostCondition(
senderAddress, FungibleConditionCode.Equal, 1000000n, sBTCAssetInfo
)
],
});
Typical Use Cases on Stacks
Bitcoin-native DeFi: lending/borrowing with sBTC as collateral. User doesn't sell BTC, uses it as collateral to get stablecoin. Protocols like Zest Protocol built exactly on this.
Bitcoin NFT: Ordinals allow inscribing data in Bitcoin transactions, Stacks adds programmable ownership and marketplace smart contracts. SIP-009 (NFT trait) — NFT standard on Stacks.
DAO and governance: Stacks suited for managing Bitcoin treasury. Multisig on Stacks with Clarity voting logic, treasury in sBTC.
Names and identity: BNS (Bitcoin Name System) built into Stacks — .btc domains registered via smart contracts.
Deployment and Mainnet
Deploying contract is on-chain transaction costing STX (network governance token). On mainnet:
clarinet deployments apply --mainnet
Contract verification is public — code visible in Explorer. No need to separately verify like on Etherscan.
Contract upgrades: Clarity contracts immutable after deploy (no proxy pattern out of the box). Upgrades possible via explicit migration pattern — deploy new contract and migrate state via on-chain calls. This makes security more predictable, but requires planning upgradability when designing.
Development Stages
| Phase | Content | Duration |
|---|---|---|
| Architecture | Contract design, sBTC integration, post-conditions | 1–2 weeks |
| Clarity contracts | Core logic development with tests in Clarinet | 3–6 weeks |
| Frontend | Stacks.js integration, Hiro Wallet / Leather wallet connect | 2–4 weeks |
| Testnet | Testnet deploy, public testing | 2–3 weeks |
| Audit | Code review, formal verification via Clarity analyzer | 2–4 weeks |
| Mainnet | Deploy, monitoring via Hiro Platform | 1 week |
Advantage of Stacks for developer from EVM world: fewer attack vectors (no reentrancy, no overflow), statically analyzable code, post-conditions as built-in protection. Trade-off: smaller ecosystem of tools, smaller developer community, specific Lisp-like Clarity syntax.







