A native Swift implementation of the Stacks.js core, for building Stacks blockchain apps on Apple platforms: key management, transaction construction and signing, Clarity values, stacking (PoX), and the Hiro API — with no JavaScript anywhere.
Every serialization path is verified against golden vectors generated by the Stacks.js test suite, including byte-identical RFC 6979 deterministic signatures.
| Stacks.js package | StacksKit | Notes |
|---|---|---|
@stacks/transactions |
✅ | STX transfer, contract call, contract deploy, post conditions, sponsored transactions, full Clarity value codec, txid, origin verification |
@stacks/wallet-sdk |
✅ | BIP-39 secret keys, BIP-32 derivation at m/44'/5757'/0'/0/n, accounts, addresses |
@stacks/network |
✅ | Mainnet, testnet, devnet, custom API nodes |
@stacks/api / node RPC |
✅ | Accounts, balances, nonces, PoX info, fee estimation with fallback, broadcast, read-only calls, transaction status |
@stacks/stacking |
✅ | delegate-stx, revoke-delegate-stx, stack-stx, pool operator calls, PoX reward address conversion (base58check + bech32/bech32m) |
@stacks/bitcoin-staking |
✅ (STX-only) | pox-5 stake, stake-update, unstake, get-staker-info, get-earned-staker-rewards, prepare-phase detection. The paired-BTC bond entry points are out of scope |
@stacks/encryption |
Partial | SHA-512/256, RIPEMD-160/hash160, HMAC, PBKDF2, secp256k1 recoverable signatures — the pieces transactions and wallets need |
@stacks/auth, @stacks/profile, @stacks/storage (Gaia), @stacks/bns, @stacks/cli |
❌ | Legacy web-app concepts, out of scope for iOS. BNS name reads are available through the Hiro API |
Multi-sig spending conditions serialize and deserialize; multi-sig signing flows are not yet implemented.
- Swift 6.2, iOS 26 / macOS 26 (matches NetworkingKit's platform floor)
- NetworkingKit 2.1.1+ for all networking
- swift-secp256k1 (
P256K) for curve operations
import StacksKit
// 24-word secret key, compatible with Xverse and Leather
let mnemonic = try generateSecretKey()
let wallet = try StacksWallet(mnemonic: mnemonic)
let account = try wallet.account(at: 0)
let address = try account.address(on: .mainnet)let transaction = try await makeSTXTokenTransfer(
recipient: Principal("SP3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159"),
amount: 1_000_000, // microSTX
senderKey: account.privateKey,
network: .mainnet,
memo: "thanks"
)
// fee and nonce are fetched automatically when omitted; pass both to build offline
let txid = try await StacksAPIService(network: .mainnet).broadcast(transaction)let transaction = try await makeContractCall(
contractAddress: StacksAddress("SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR"),
contractName: "amm-pool-v2-01",
functionName: "swap",
functionArgs: [.uint(100_000), .principal(pool), .none],
senderKey: account.privateKey,
network: .mainnet,
postConditions: [
.stx(principal: .origin, condition: .lessEqual, amount: 100_000),
]
)let stacking = StackingClient(network: .mainnet)
let info = try await stacking.poxInfo() // reads the live pox contract id
guard let burnHeight = info.currentBurnchainBlockHeight,
!info.isInPreparePhase(atBurnHeight: burnHeight) else { return } // stake reverts in the prepare phase
// Bind STX to a signer-manager (the pool). The STX locks at your own address;
// rewards are paid in sBTC on the operator's terms.
let stake = try await stacking.stake(
signerManager: Principal("SP8HK160YD5GHXP69VGA0TC7AQJ1X4CDW3XVERSE.xverse-signer-manager-3"),
amountMicroStx: 500_000_000_000,
numCycles: StackingClient.maxStakeCycles, // 96 = earn until you unstake
startBurnHeight: burnHeight,
senderKey: account.privateKey
)
let txid = try await stacking.broadcast(stake)
// Later: top up, or end the stake at the cycle boundary.
if let position = try await stacking.pox5StakerInfo(for: address) {
_ = try await stacking.stakeUpdate(signerManager: position.signer, oldSignerManager: position.signer,
amountIncreaseMicroStx: 100_000_000, senderKey: account.privateKey)
_ = try await stacking.unstake(oldSignerManager: position.signer, senderKey: account.privateKey)
}The pox-4 delegate-stx family is still available for legacy reads and builders, but mainnet retired delegation with pox-5.
let api = StacksAPIService(network: .mainnet)
let balances = try await api.balances(address)
let result = try await api.callReadOnly(
contract: try info.contract(), // whatever /v2/pox reports — never hardcode pox-N
functionName: "get-staker-info",
functionArgs: [.principal(try Principal(address))]
)swift test runs 72 tests covering:
- NIST vectors for SHA-512/256 and the reference vectors for RIPEMD-160
- BIP-39 (Trezor vector) and the
@stacks/wallet-sdkend-to-end derivation vector - c32 / c32check address vectors from the Stacks.js
keystests - Byte-for-byte transaction golden vectors from the Stacks.js
buildertests: mainnet transfer, testnet transfer, contract call, and sponsored transfer including the placeholder sponsor condition and exact origin signature - pox-5
stake/stake-update/unstakeand pox-4delegate-stxgolden vectors generated with@stacks/transactions7.6.0, signatures included - Clarity value wire-format vectors and round-trips for every value shape
- Bitcoin address decoding (BIP-173/BIP-350 vectors) for PoX reward addresses