BULL app icon

Wallet descriptors, Liquid swaps, exchange orders

Getting Bitcoin, Liquid and exchange history out of BULL Bitcoin Mobile

Two wallets come out of a single BIP39 seed in BULL, and both leave a trail you can reconstruct without ever touching the app's screens. The Secure Bitcoin Wallet is descriptor-based, so its on-chain history backfills from one output descriptor against an Electrum server. The Instant Payments Wallet does the same on the Liquid Network, once its blinding key unblinds the confidential amounts. So the starting point for an integration here is a bulk historical scan, not a polling loop bolted on after the fact.

Behind the wallet sits a second, separate surface: the app's authenticated session against Bull Bitcoin's exchange backend, which carries buy and sell orders, recurring DCA schedules, fiat funding, and payout records. The route we take reads the chain side straight from descriptors and standard protocols — the client is open source, so the structures are documented rather than guessed — and reaches the exchange side through the user's own consented session. The two join on one thing: the payout address the app generates and hands the server when it buys.

What BULL holds and where it lives

Each row below is a real surface in the app, not a generic feed. Some of it is on the public chain and only needs the right descriptor; some sits behind the account and needs a consented session.

Data domainWhere it originatesGranularityWhat an integrator does with it
On-chain Bitcoin transactions and UTXOsSecure Bitcoin Wallet output descriptor (bech32 segwit)Per-UTXO and per-transaction, with confirmation heightBalance reconciliation, cost-basis, accounting export
Liquid (L-BTC) transactionsInstant Payments Wallet, confidential segwitPer-transaction; amounts and assets unblinded with the blinding keyPayments ledger, L-BTC balance tracking
Lightning paymentsBoltz atomic swaps (submarine and reverse)Per-swap: invoice, preimage, status, on-chain/Liquid legsReconcile payments across the Lightning and Liquid layers
Exchange orders and DCAAuthenticated Bull Bitcoin sessionPer-order fiat amount, rate, status; DCA cadence configTreasury and portfolio sync
Payouts and bitcoin deliveryApp-supplied payout address sent to the serverPer-payout address, amount, settling txidDelivery tracking; join orders to settled coins
Account and fundingExchange session (e.g. Interac funding)Profile, KYC tier, funding eventsCompliance records, treasury context
Labels and metadataBIP-329 label exportPer-output and per-transaction labelsEnrich the normalized ledger with human context

Authorized ways in

Public source plus descriptors and chain

The on-chain Bitcoin and Liquid history reads directly from the wallet's output descriptors and blinding key against an Electrum backend and the Liquid chain. This is the durable backbone: it rides standard BIPs and an MIT-licensed client, so it does not break when a screen is redesigned. We handle the descriptor and blinding-key derivation as part of the build, working from the exports the wallet already produces.

Authorized analysis of the exchange session

Orders, DCA schedules, funding and payout records live behind the app's authenticated session to Bull Bitcoin's servers. We map the request and response shapes for that session under the user's consent. Durability here is moderate — the platform changed materially with the April 2025 rebuild, per Bull Bitcoin's own announcements — so we version this reader and keep it easy to re-map.

Native export as a fallback

The app already emits BIP-329 labels and supports PSBT, xpub and watch-only exports. When a live session is not in scope, these fill gaps and enrich the ledger. They are a complement, not the main channel.

For most use cases we would build the chain-and-descriptor reader first and treat it as the dependable core, since that is the part least likely to shift under you, then add the exchange-session reader for the fiat side and keep native exports as a backstop. We make that call concrete during scoping for what you actually need from the data.

A backfill pass, in code

This sketch mirrors how the app itself syncs the Secure Bitcoin Wallet — a BDK descriptor scan against an Electrum server. Field names below were checked against the public SatoshiPortal/bullbitcoin-mobile source; treat the snippet as illustrative of the real surface, not a drop-in.

# Bulk-backfill BULL's Secure Bitcoin Wallet from its output descriptor.
# bdk-flutter in the app; bdkpython here for a server-side reader.
from bdkpython import Wallet, Descriptor, Blockchain, ElectrumConfig, Network

wallet = Wallet(
    descriptor        = Descriptor(SECURE_WALLET_DESC, Network.BITCOIN),    # wpkh(...), bech32, exported from the app
    change_descriptor = Descriptor(SECURE_WALLET_CHANGE, Network.BITCOIN),
    network           = Network.BITCOIN,
    database_config   = sqlite_config("bull_secure.db"),
)

# Default backend is an Electrum server; the app reads fees from a mempool instance.
chain = Blockchain(ElectrumConfig(url=ELECTRUM_URL, stop_gap=50, timeout=10, retry=3))
wallet.sync(chain)            # full historical scan on first run; incremental thereafter

ledger = []
for tx in wallet.list_transactions(include_raw=False):
    ct = tx.confirmation_time
    ledger.append({
        "txid":     tx.txid,
        "net_sat":  tx.received - tx.sent,
        "height":   ct.height    if ct else None,     # None == still in mempool
        "ts":       ct.timestamp if ct else None,
        "label":    labels.get(tx.txid),              # BIP-329 export, if the user shares one
    })

# Liquid side: same shape, but unblind with the wallet's blinding key first,
# or confidential amounts read back as zero. Lightning is reconstructed
# separately from Boltz swap records (invoice, preimage, on-chain/Liquid legs).

What you get back

The headline deliverable is code that runs against this app's actual surfaces, not a document about it:

  • Runnable backfill client (Python or Node.js) — scans the Secure Bitcoin Wallet from its descriptor via Electrum, unblinds the Liquid wallet, and reconstructs Boltz swap history into one ledger.
  • Exchange-session reader — pulls order, DCA, funding and payout records from the authenticated Bull Bitcoin session and joins them to wallet receives on the shared payout address.
  • Automated test suite — fixtures over known descriptors and recorded swap and session responses, covering the descriptor scan, the unblinding step, and the order-to-coin join.
  • Normalized schema and sync design — the unified ledger shape, idempotent re-runs keyed on txid and swap id, and the batch-then-delta plan for keeping the feed current after the first backfill.
  • An OpenAPI-style map and auth-flow notes for the exchange session — the token and cookie chain, plus the descriptor and blinding-key derivation — written up alongside the code.
  • Interface documentation and data-retention guidance: how consent and logging are recorded, what is minimized, and an NDA where the work needs one.

One ledger, normalized

Chain receives, Liquid transfers, Lightning swaps and exchange buys all collapse into one row shape, so downstream systems do not care which layer a movement came from. The order-to-coin join shows up as a field rather than a separate report:

{
  "source":      "bull.secure_wallet",     // or bull.instant_wallet / bull.exchange
  "type":        "onchain_receive",         // onchain_send | liquid_xfer | ln_swap | buy | sell | dca
  "txid":        "9f3c…b21a",
  "amount_sat":  120000,
  "asset":       "BTC",                     // BTC | L-BTC
  "settled_at":  "2026-05-30T11:04:00Z",
  "linked_order":"bb_order_7K…",            // present when a payout address matches an exchange buy
  "swap":        null                       // populated for ln_swap: { invoice, preimage, status }
}

What we account for on this build

A handful of things about BULL specifically shape the integration. We handle each as part of the work, not as something you have to prepare first.

  • Liquid amounts are blinded. Confidential transactions hide value and asset on the wire, so we derive the wallet's blinding key from the same seed material and unblind during the sync; without that step L-BTC balances and Lightning-via-Liquid receives read as zero.
  • Lightning is a swap trail, not a channel database. Because incoming Lightning is converted to Liquid bitcoin through Boltz, we rebuild that activity from submarine and reverse swap records and model the swap state machine, so a pending swap is never double-counted against the on-chain leg.
  • Two backends, one join key. Chain data and exchange data come from different places; we tie an order or DCA buy to the coins that landed by matching the payout address the app supplies to the server. Access to the authenticated session is arranged with you during onboarding, against a consenting account.
  • Open source cuts the guesswork. Since the client is published on GitHub, we map field names and request shapes from source and confirm them against live traffic, rather than inferring everything from captured packets.

Authorization, and the Canada/EU picture

The dependable basis for this work is the user's own authorization over their own data. On-chain and Liquid records belong to the wallet holder and are read from their descriptors and the public chain; anything behind the account is reached only through that person's consented session. In Canada the operator is Satoshi Portal Inc., listed on FINTRAC's money-services-business registry (registration M16730720, per the public MSB listing); in the European Union, Bull Bitcoin operates through Leonod SARL under an AMF registration, per its terms. Canada's consumer-driven banking framework is still being stood up and is aimed at banks rather than a self-custodial wallet, so it is not the hook for this integration — consent and the open-source codebase are. We keep access logged, minimize what we touch, and sign an NDA where the engagement calls for one.

Screens from the app

Store screenshots, useful for matching on-screen labels to the fields we extract.

BULL screenshot 1 BULL screenshot 2 BULL screenshot 3 BULL screenshot 4 BULL screenshot 5 BULL screenshot 6
BULL screenshot 1 enlarged
BULL screenshot 2 enlarged
BULL screenshot 3 enlarged
BULL screenshot 4 enlarged
BULL screenshot 5 enlarged
BULL screenshot 6 enlarged

Same neighbourhood, different shapes — useful when an integration has to cover more than one wallet at once.

  • Aqua Wallet — a Bitcoin, Liquid, Lightning and Tether wallet now under JAN3; like BULL's Instant Payments side it holds confidential Liquid balances.
  • Blockstream Green — multi-wallet Bitcoin with built-in Liquid support for L-BTC and Liquid assets, plus Lightning and 2FA accounts.
  • Phoenix — a self-custody Lightning wallet with an embedded node, so its history is channel- and payment-centric.
  • Breez — a non-custodial Lightning client whose records are per-payment rather than per-channel.
  • Muun — a Bitcoin and Lightning wallet that presents on-chain and Lightning funds as a single balance.
  • Cake Wallet — an open-source multi-asset wallet covering Bitcoin, Monero and Litecoin with built-in exchange flows.
  • Sparrow Wallet — a desktop-leaning Bitcoin wallet built around descriptors, PSBT and coin control, strong for accounting exports.
  • Electrum — a long-running Bitcoin wallet with seed and descriptor recovery and server-based transaction history.
  • Proton Wallet — a self-custody Bitcoin wallet with end-to-end encrypted metadata.
  • Coldcard — an air-gapped hardware signer that pairs with software wallets over PSBT and xpub watch-only.

Questions integrators ask about BULL

Can BULL's on-chain and Liquid history be backfilled in one pass, or does it need constant polling?

One bulk pass does most of the work. The Secure Bitcoin Wallet is descriptor-based, so a full historical scan against an Electrum backend recovers every address and transaction it has touched; after that, only incremental syncs are needed. The Liquid side works the same way once the wallet's blinding key unblinds the confidential amounts. We design the first run as a backfill and everything after it as a delta.

If Lightning rides atomic swaps, how does the payment history get reconstructed?

BULL receives Lightning through Boltz, which swaps the incoming payment into Liquid bitcoin behind the scenes. There is no channel database to read. Instead we rebuild Lightning activity from the swap records — the invoice, the preimage, and the on-chain or Liquid legs — and model the swap states so a pending swap is not counted twice.

Can a buy or DCA order be tied back to the coins that actually landed in the wallet?

Yes. When the app buys bitcoin it generates a receiving address and hands it to Bull Bitcoin's servers as the payout target, and the coins are delivered straight to the wallet. That shared address is the join key: order and DCA records from the authenticated exchange session line up with the on-chain receive, so a unified ledger can show both the fiat side and the settled coins.

Who operates BULL, and does that change how access is authorized?

In Canada the operator is Satoshi Portal Inc., listed on FINTRAC's money-services-business registry; in the European Union it runs through Leonod SARL under an AMF registration. On-chain and Liquid data is the user's own and is read from their descriptors and the public chain. Anything behind the exchange account — orders, funding, KYC status — is reached through the user's own consented session, which we arrange with you during onboarding.

Where this comes from

I read the open-source client and the operator's own posts, and confirmed the regulatory entities against public registries, on 2026-06-15. Primary references: the bullbitcoin-mobile README (wallet structure, BDK/LWK/Boltz stack); Bull Bitcoin's note on using Liquid for Lightning without channels; its post on Canadian MSB regulation; and the FINTRAC MSB listing for Satoshi Portal Inc.

Compiled by OpenFinance Lab — interface assessment, 2026-06-15.

A first working backfill — runnable source against the descriptors, the swap reconstruction, and the exchange-session reader — lands inside one to two weeks. Take it as delivered source code starting at $300, paid only once the integration runs and you are satisfied; or skip the build and call our hosted endpoints, paying per call with nothing upfront. Tell us the app and what you want from its data on the contact page, and we scope it from there.

App profile: BULL (Bull Bitcoin Mobile)

BULL is a self-custodial wallet for Bitcoin and the Liquid Network, with non-custodial atomic swaps across Bitcoin, Lightning and Liquid. From one BIP39 seed it generates a Secure Bitcoin Wallet (descriptor-based, for savings and everyday use) and an Instant Payments Wallet (Liquid-based, for low-cost Lightning payments without channel management). It is open source under the MIT license, built in Dart/Flutter on BDK, LWK and Boltz, and pairs with Bull Bitcoin's non-custodial exchange for buying, selling and DCA. The package id is com.bullbitcoin.mobile, per its Play Store listing; the operator is Satoshi Portal Inc. in Canada and Leonod SARL in the EU. This recap is neutral background for the integration notes above.

Last checked 2026-06-15