Documentation Index
Fetch the complete documentation index at: https://docs.arkadeos.com/llms.txt
Use this file to discover all available pages before exploring further.
Arkade integrates with Boltz chain swaps so you can move funds between Bitcoin onchain UTXOs and Arkade VTXOs.
Overview
The BoltzSwapProvider extends Arkade contracts with two chain swap flows:
- Bitcoin to Arkade swaps - Receive BTC onchain and claim into your Arkade wallet
- Arkade to Bitcoin swaps - Send from your Arkade wallet to a Bitcoin address
This guide mirrors the Lightning swap workflow and uses the same @arkade-os/boltz-swap package.
Installation
pnpm add @arkade-os/sdk @arkade-os/boltz-swap
Basic usage
Initializing the Chain Swap Provider
import { Wallet } from '@arkade-os/sdk'
import { ArkadeSwaps, BoltzSwapProvider } from '@arkade-os/boltz-swap'
// Initialize your Arkade wallet
const wallet = await Wallet.create({
identity,
arkServerUrl: 'https://arkade.computer',
})
// Initialize the chain swap provider
const swapProvider = new BoltzSwapProvider({
apiUrl: 'https://api.ark.boltz.exchange',
network: 'bitcoin',
})
// Create chainSwaps instance
const chainSwaps = new ArkadeSwaps({
wallet,
swapProvider,
})
Checking limits
Before creating a chain swap, validate the supported range:
const limits = await chainSwaps.getLimits('ARK', 'BTC')
// => { min: number, max: number }
if (limits) {
console.log('Minimum:', limits.min, 'sats')
console.log('Maximum:', limits.max, 'sats')
const amount = 50_000
if (amount < limits.min) {
console.error(`Amount ${amount} is below minimum ${limits.min}`)
} else if (amount > limits.max) {
console.error(`Amount ${amount} is above maximum ${limits.max}`)
}
}
Checking fees
You can estimate fees for a proposed chain swap amount:
const calculateSwapFee = async (satoshis: number): Promise<number> => {
if (!satoshis) return 0
const fees = await chainSwaps.getFees('ARK', 'BTC')
// => { percentage: number, minerFees: { server: number, user: { claim: number, lockup: number } } }
if (!fees) throw new Error('Unable to fetch fees')
return Math.ceil(
(satoshis * fees.percentage) / 100 + fees.minerFees.server + fees.minerFees.user.claim + fees.minerFees.user.lockup,
)
}
Receiving BTC payments (Bitcoin → Arkade)
When setting amount, choose one mode:
senderLockAmount: sender pays exactly this amount; you receive less after fees
receiverLockAmount: you receive exactly this amount; sender pays more including fees
const result = await chainSwaps.btcToArk({
receiverLockAmount: 5_000,
})
// => { btcAddress: string, amountToPay: number, pendingSwap: { id: string; preimage: string; amount: number; /* more fields per PendingChainSwap */ } }
console.log('BTC deposit address:', result.btcAddress)
console.log('Amount to pay:', result.amountToPay)
console.log('Pending swap:', result.pendingSwap.id)
Monitoring incoming BTC payments
const { txid: claimTxid } = await chainSwaps.waitAndClaimArk(result.pendingSwap)
console.log('Claim successful:', claimTxid)
Sending BTC payments (Arkade → Bitcoin)
const result = await chainSwaps.arkToBtc({
receiverLockAmount: 5_000,
})
// => { arkAddress: string, amountToPay: number, pendingSwap: { id: string; preimage: string; amount: number; /* more fields per PendingChainSwap */ } }
const txid = await wallet.send({
address: result.arkAddress,
amount: result.amountToPay,
})
Monitoring outgoing BTC payments
const { txid: payoutTxid } = await chainSwaps.waitAndClaimBtc(result.pendingSwap)
console.log('Payout successful:', payoutTxid)
Checking swap status
const { status } = await chainSwaps.getSwapStatus('swap_id')
// => swap.created, swap.expired, transaction.mempool, etc...
console.log('Swap status:', status)
Storage
Swap records are persisted through the wallet contract repository:
const pendingChainSwaps = await chainSwaps.getPendingChainSwaps()
const chainSwapHistory = await chainSwaps.getSwapHistory()
// => Array<{ id: string; preimage: string; amount: number; /* more fields per PendingChainSwap */ }>
Cleanup
ArkadeSwaps implements a disposable lifecycle:
const chainSwaps = new ArkadeSwaps({ wallet, swapProvider })
// ... use it
await chainSwaps.dispose()
Error handling
Handle known swap failures explicitly and refund when possible:
import {
SwapError,
SchemaError,
NetworkError,
SwapExpiredError,
InsufficientFundsError,
TransactionFailedError,
} from '@arkade-os/boltz-swap'
try {
const result = await chainSwaps.arkToBtc({
receiverLockAmount: 5_000,
})
await wallet.send({
address: result.arkAddress,
amount: result.amountToPay,
})
await chainSwaps.waitAndClaimBtc(result.pendingSwap)
} catch (error) {
if (error instanceof InsufficientFundsError) {
console.error('Insufficient funds:', error.message)
} else if (error instanceof NetworkError) {
console.error('Network issue:', error.message)
} else if (error instanceof SchemaError) {
console.error('Invalid provider response')
} else if (error instanceof SwapExpiredError) {
console.error('Swap expired. Create a new swap request.')
} else if (error instanceof TransactionFailedError) {
console.error('Transaction failed')
} else if (error instanceof SwapError) {
console.error('Swap failed:', error.message)
} else {
console.error('Unknown error:', error)
}
if (error instanceof SwapError && error.isRefundable && error.pendingSwap) {
const { txid: refundTxid } = await chainSwaps.refundArk(error.pendingSwap)
console.log('Refund claimed:', refundTxid)
}
}