Today I was able to get Wallet of Satoshi beta version 3.0.19 in the United States region. The app has a new "self-custody" mode powered by Spark. My honest review and testing are found below.
2025-08-16
Wallet of Satoshi started out as a fully custodial bitcoin and lightning wallet. I wrote it off completely because I like to own my own money. The wallet was kicked out of the United States Google Play Store for a while and recently came back with developers claiming they managed to make it non-custodial ("self-custodial"). They integrated a novel statechain protocol called Spark, and this is how the app claims self-custody while saving the user from lightning channel maintenance.
It is tempting to compare Spark-integrated wallets with other types of wallets that attempt to make the lightning network easier to use. For example, Aqua and Misty Breez both use a combination of the Liquid sidechain and the Boltz bridge to simulate self-custody lightning without end-user channel maintenance. Instead of the user owning BTC inside their own lightning channels, they own something else, and some other component manages those channels for them.
Spark has some important benefits over Liquid. The Liquid federation has full control over the BTC to L-BTC bridge and can issue unbacked L-BTC or refuse redemptions. L-BTC is a custodial I.O.U. and Liquid wallets are categorically custodial, despite what the marketing materials might say. The Spark service provider on the other hand cannot issue an unbacked BTC substitute or prevent the user from exiting. Spark is also not a blockchain, which could make it more scalable than Liquid. Spark wallets still share some problems in common with Liquid + Boltz wallets. Transactions are still processed by a federation, the federation can always refuse to process any transaction, lightning payments sometimes fail to route through the network, and there is still a small risk of theft.
The Spark protocol was criticized by Bitcoin Magazine and Bitcoin Layers for stuffing a trusted federation under the mattress. If you receive funds over Spark, and the previous owner colludes with the federation, your funds can be stolen. Then there's the remaining issue that you can't really force anything through Spark except withdrawal. A good payment system should let me force any payment I want (permissionless), and it should be verifiably unable to steal from anyone (non-custodial). Spark might be a little bit better than Liquid, but it still doesn't fully satisfy these criteria.
Spark also reminds me of Ark. There are several designs for Ark with or without covenants, and they share common characteristics. In Ark, like with Spark, the user owns VTXOs on a statechain. All the same, those VTXOs become more expensive to unilaterally exit the more they change hands. The key difference with Ark is that they can be exchanged for fresh ones at any time, and the user must eventually do this before they expire. Fresh VTXOs are cheaper to force on-chain and they carry no risk of being stolen by previous owners colluding with the service provider. With Spark, we don't have the option to do this, but we are also not required to do it either. I wonder what else a Spark user could do to maintain VTXO freshness.
I used WoS to receive some lightning payments, then I installed WoS on a different phone and restored from seed. This ended up repopulating my balance and full history. I was able to use my funds on both installations at the same time without any issues.
On Bitcoin Layers it says,
Data related to current UTXO ownership is held client-side
Transaction data is self-hosted. The statechain entity signs individual transactions and users store data for their keyshare and unilateral exit path client-side. The statechain entity also keeps a record of transfer history.
Something was done to associate my VTXO ownership on the server-side, and restoring from seed was able to retrieve it. This calls into question how much privacy I have or whether it differs from other Spark integrations.
Wallets like Aqua and Misty Breez internally use a Liquid wallet address to store user funds. If the user receives a BTC or lightning payment, it gets routed through Boltz and the user really receives L-BTC. The reverse is true when the user sends a payment. The seed phrase in either wallet can be loaded in any other Liquid wallet and the user can directly interact with the underlying Liquid address.
In the case of WoS, the wallet internally keeps a BTC taproot address. The purpose of the taproot address is very different. Under normal operations, this is where on-chain funds enter and exit for the particular user. If you don't use Spark to interact with on-chain, you'll never see anything happening to the taproot address. Even if you do bring money in through this address, you can't directly access it by just importing your WoS seed phrase into another wallet. You can only interact with any money that might be in it by performing the unilateral exit ritual, if the implementation provides it.
I sent some funds to the taproot address. WoS acknowledged the deposit after 2 confirmations but didn't credit my balance until 3 confirmations. After depositing funds and seeing what would happen, it was time to send the money back where it came from. I am totally at the mercy of how WoS decides to craft the withdrawal transaction. I don't have control over fees or fee bumping. I also can't bypass it by sneaking my seed into a different taproot wallet and doing whatever I like, since the taproot address is in a shared ownership situation between myself and the Spark service provider.
WoS charged me a withdrawal fee that would normally cover two on-chain transactions. In fact, the funds traveled from the original WoS taproot address to an intermediary address before a second transaction was dispatched to my chosen withdrawal destination, with two additional outputs headed for other destinations. It appears that the Spark service provider leaves my taproot funds idle and issues VTXOs against them until I go to withdraw. Then, it moves those taproot funds to a staging location, siphons off an additional fee, and sends the rest to my chosen destination. Withdrawing cooperatively from Spark requires two on-chain operations.
Another note on on-chain footprint: Liquid and Spark wallets are designed to pay the Bitcoin miners as little as possible by minimizing their on-chain footprint. This is not great for the security budget of the network. Protocols like Spark and scam networks like Liquid do not solve all of Bitcoin's problems.
Some lnurl providers let you set a vanity address on their domain. WoS lets me have any unused name @walletofsatoshi.com after I perform enough actions inside the app. Otherwise they give me a random one. There is a way to bypass this by forwarding an arbitrary name on my own domain to the name provided in the app. The method seems to work fine with some wallets but not others.
See how I am forwarding the name "goatmeal@apathy.tv" to "npub1g0atme30l6s65rw6ulq2cqahq9lzmpj0sejhsjcqh0azlyg5cp4qf7gqpz@npub.cash." I got the details by visiting https://npub.cash/.well-known/lnurlp/npub1g0atme30l6s65rw6ulq2cqahq9lzmpj0sejhsjcqh0azlyg5cp4qf7gqpz and in my case, my well-known directory lives inside my peertube website.
To test if I can alias my goofy ahh random walletofsatoshi name, I visited https://walletofsatoshi.com/.well-known/lnurlp/thenametheygaveme in a browser and transferred the details to a new file in my well-known directory. Then I tried sending a payment to it, and it succeeded.
Interestingly, this is the only way I'm able to see the internal Spark address. The app didn't show it anywhere. And here's some bad news: the Spark address shows up on a block explorer with my balance and all my transaction history. Anyone can see this from inspecting my lnurl. Spark by itself doesn't really give me any extra privacy.
Here's what I like:
Here's what I don't like:
Here's what I still want to know:
Bonus:
The marketing materials for Aqua and Misty Breez are still covered in lies and deceptive language. "Permissionless," "full control," "self custody," "privacy." Fuck these people.