The third Swift layer for BSV, above two that already exist:
| Layer | Repo | What it holds |
|---|---|---|
| Primitives | swift-sdk |
keys, crypto, transactions, BEEF, the BRC-100 ABI |
| Generic wallet | swift-wallet-toolbox |
remote storage, the action lifecycle, RemoteWallet |
| 1Sat ecosystem | this | ordinals, BSV21 tokens, OpNS, MNEE, sweep — the protocol-specific actions |
It is the Swift counterpart of b-open-io/1sat-sdk and the
@1sat/* packages. It depends on both layers below it.
Early. The first modules cover sweep — moving coins from a foreign or legacy key into a wallet's own address — and read-only ordinal and BSV-21 balances for wallet displays. Sweep is generic over source, destination, and UTXO provider; the client reads categorised owner outputs from the 1Sat indexer.
Next, in the order the wallet app needs them: 1Sat ordinal templates and transfer actions, then BSV-21 transfers, OpNS, and MNEE.
| Module | Responsibility |
|---|---|
OneSatClient |
Read an address's ordinals and aggregate BSV-21 token balances |
OneSatSweep |
Categorise an address, sweep its fundable BSV, report the rest |
OneSat |
Umbrella, re-exporting the above |
A sweep is partial by nature. A legacy address rarely holds only plain BSV — it may hold ordinals, BSV-21 tokens, and time-locked outputs. Sweeping all of them would burn a collectible as a fee or build an invalid transaction. So the safe flow categorises first, sweeps the fundable BSV, and reports what remains — keeping the source key while any asset is still there, exactly as Yours Wallet's migration does.
import OneSatSweep
// 1. Categorise through the 1Sat indexer (the only provider that can tell an ordinal from a coin).
let plan = try await Sweep.plan(forAddress: legacyAddress, scanner: OneSatScanner())
// 2. Sweep only the fundable BSV.
if !plan.fundable.isEmpty {
let result = try Sweep.build(fromWIF: legacyWIF, toAddress: myWalletAddress, utxos: plan.fundable)
// broadcast result.transaction
}
// 3. Keep the key while anything remains; re-sweep after the next lock unlocks.
if !plan.remaining.isEmpty {
// preserve legacyWIF; plan.remaining.nextUnlockHeight tells you when to try again
}| Family | Gives | Use for |
|---|---|---|
| WhatsOnChain | plain UTXOs, no asset tags | balance, plain-BSV-only sweep (WhatsOnChainUTXOSource) |
1Sat / GorillaPool (api.1sat.app, junglebus, Banana Blocks) |
UTXOs with event tags (bsv21:, lock:, ordinal) |
any sweep that could hold assets (AssetScanner) |
A sweep that might touch assets must read from the 1Sat family — WhatsOnChain cannot tell a
high-value ordinal from a coin. The wallet's provider setting selects which family answers. Both adapters are built and
live-verified: WhatsOnChainUTXOSource and OneSatScanner (api.1sat.app).
swift build
swift test