I’ve decided to work on multi-store support now since I’d like to avoid merchants having to go through two different migrations for both mempool notifications and multi-store support. Also, the new RPC API supports multiple accounts, so retrofitting it to work with the existing single-account model in the plugin feels messy.
Am happy to include this work as part of the last milestone and would be keen on applying for retroactive funding in a future grant for the plugin multi-store work together with reaching out to BTCPayServer hosts for them to be able to offer ZEC support. This might be a good way to onboard physical merchants who would like to use a third party BTCPay host for Point of Sale functionality.
I have both multi-store and mempool notifications working locally, there is still some work needed though with ironing out bugs and cleaning up the codebase. I’d like to get regtest mode and integration tests working to make future development work easier.
For shielded payments, does the 0conf notification fire when the merchant wallet spots the incoming note in the mempool, or does the server need a viewing key to see it before the block confirms?
I didn’t quite understand your question. The wallet RPC needs a Unified Viewing Key to be able to decrypt the transaction from the mempool as it is a shielded transaction. It detects the correct payment by using the diversified address generated for the invoice. The notification fires around a second after the payment has been sent.
Ironwood transactions and post-NU6.3 sync are now supported thanks to a contribution from Nano-GPT to zcash-walletd. Run the btcpay-update.sh script to upgrade to it.
I have implemented an RPC API in Rust on top of the Zkool crate instead of wrapping the GraphQL API. This approach has proved much faster and more stable during testing. Repo: GitHub - elemental-pay/zcash-wallet-rpc · GitHub
Multi-store and mempool notifications are working locally. I am currently focused on testing the stability and various edge cases such as incomplete transactions, and on creating a migration pathway for existing stores to switch to the new Zkool based RPC server. There should be an alpha release published to Docker by the end of this week with a custom Docker fragment allowing users/merchants to test it.
— Edit —
I plan to make an initial release of zcash-wallet-rpc that is compatible with existing BTCPayServer versions and imports config.json into “Account 1”. Multi-store will be published after the grant is completed. Each store will need a unique viewing key.
BTCPayServer Zcash plugin mempool support is now live on the Elemental Pay Test BTCPay Instance and ready for testing. An alpha version has been published to Docker: 1337bytes/zcash-wallet-rpc:alpha
A migration script handles importing an existing wallet database (to extract the diversifier index to prevent regenerating existing diversifier addresses) and viewing key. There is no BTCPayServer plugin update necessary currently, as zcash-wallet-rpc handles the automatic migration of “Account 1” and a temporary measure of rewriting account_index: 0 request parameters to account_index: 1.
Existing merchants are requested not to upgrade on a main instance until community testing and code review has taken place.
My original proposal and deliverable was specific about implementing a new RPC API to be consumed by the plugin (zkool-walletd, which has now pivoted to zcash-wallet-rpc). I feel that a rewrite of the plugin to use GraphQL, over RPC, would likely have been more work and harder to test, there is more documentation and reference BTCPay plugin code for RPC implementations.
I’d like for merchants to have a choice between wallet daemons, for example to continue using zcash-walletd, or point their BTCPay instance to a Cipherpay RPC, rather than be tied to a GraphQL implementation.
I started work on the zkool-walletd Node.js GraphQL wrapper before applying for this grant and was hoping to make use of this work. You are right that having three different layers introduces too much complexity and I’ve since replaced the JS layer with Rust (zcash-wallet-rpc). A rewrite in the .NET plugin would delay things even further.
The GraphQL API doesn’t have a transactions/notes filter by subaddress or store of every Orchard/UA diversified receiver. I’d like to avoid storing such indexing data in the BTCPayServer database (outside of a store blob). If a historic diversified address/receiver store can be contributed upstream to Zkool, that would make integrating the GraphQL API in the plugin more straightforward.
I appreciate your additions and maintenance of the GraphQL API; has been a big help. If you’d prefer for me not to consume Zkool crate internals and would be ok with me contributing functionality such as an address receiver store upstream, I could start work on adding a GraphQL interface on the plugin side. I’d like to keep the option of an RPC interface though.
I’m committed to improving the BTCPay plugin/integration long term, hence my preliminary work on the multi-store implementation and am working towards onboarding new merchants.
Simply put, I prefer that the BTCPayServer plugin logic stays in C# like the rest of BTCPayServer.
The GraphQL API doesn’t have a transactions/notes filter by subaddress or store of every Orchard/UA diversified receiver. I’d like to avoid storing such indexing data in the BTCPayServer database (outside of a store blob). If a historic diversified address/receiver store can be contributed upstream to Zkool, that would make integrating the GraphQL API in the plugin more straightforward.
What’s the difference between subaddress and div index? I am not sure you need a mapping.
In general, isn’t storing plugin data in the BTCPayServer database the recommended way (need to consult the BTCPayServer devs)?
The Zcash plugin stands out by going c# → rust → rust. It seems to be arbitrary, and chosen to avoid working with the BTCPayServer code. As such, the plugin looks like an adaptation of the Monero plugin and then branch out to rust ASAP. IMO, that’s not an architecture that conforms with the rest of the app. I think it’s important for maintenance and complexity that it doesn’t introduce extraneous layers. Besides, it seems to be an easy task for AI to get rid of the proxy.
This appears to only affect Bitcoin/Lightning hot wallets, Zcash plugin should be unaffected since it’s watch-only, but it’s worth updating to 2.4.2 ASAP anyway.
You’re going to want to explicitly destroy your macaroons and macaroons.db and recreate them fresh. This also applies to auth mechanisms for other LN backends.
Also, if you generated a hot on-chain wallet in BTCPay you want to move those funds.
Deliverables:
- zkool-walletd RPC
- multi-account support via RPC API
- mempool notifications (0conf support)
- switch and update plugin to use zkool-walletd for mempool notification support
This should have been raised before I started work on the grant. I don’t feel that one month worth of compensation is enough to rearchitect the entire plugin.
I am asking for considerably less compensation than was requested for the initial development of the plugin. I’ve been active in providing year-round support to all of the merchants and have asked for a modest amount of funding.
I have started work on creating a GraphQL client/adapter for the plugin, but this will take some time; I’d like to keep the RPC interface to allow for merchants to choose the wallet backend rather than strip it out. As this amount of work would be larger than that of multi-store support, I feel it would be fair to request retroactive funding for this work in the future.
I think you are fighting the btcpay server plugin model by introducing another component that sits between the plugin and the wallet app. It is making your design more complex than needed since you have to replicate part of the data model from c# to rust. And it has to be tested, etc.
Is this because you feel like graphql isn’t as easy to work with in c# than rust?
That shouldn’t be the case. Graphql.net is a mature project with 6k stars on github.
We seem to be going around in circles. I’m not disagreeing with you. I originally asked for 42k, then reduced the total to 25k to create a minimal viable product, cutting out multi-store support and working on the solution which would take me the least time: an RPC server together with minimal plugin maintenance and bug fixes. Everyone seemed happy with this.
You haven’t answered me about why you didn’t raise this before I started work on the grant. As I understand, you abstained from voting due to the conflict of interest, but this would have been the appropriate time to raise a discussion rather than now.
I ended up working on multi-store support under my own time/expense to avoid retrofitting Zkool multi-account support to a single account system. I committed to maintaining this project long-term and proactively offering support to both existing merchants and finding new merchants, who have all been happy with my work.
I’ve started work on a GraphQL client for the plugin. If you feel strongly that time/energy should be invested into this approach, I feel that it’s fair to compensate the 42k for the original proposal, given that the entire data model and event cycle of the plugin needs to be rearchitected. More work is required from my end, than for the originally proposed multi-store support.
I didn’t raise this because it was obvious to me that the client code would be in the btcpay server plugin. I had no idea you intended to add a component that bridges rest to graphql.
I don’t really get your reluctance to work in C# but that’s fine, to each their own. Unfortunately Btcpayserver is a C# app so it doesn’t seem to be a good fit.
You seem to be questioning my competency in maintaining this project?
I stepped in to defend your work when Sunny was criticising it even though there were valid points made re the fact the plugin integration was left incomplete and with zero merchant adoption until I took over the project. You also seemed reluctant to work in C# and retrofitted the RPC API to that of the Monero RPC.
Zcash Community Grants Meeting Minutes 5/11/2026
Were you present during this meeting? My approach was clear from the start. Do you feel that it’s fair for me to now ask for additional compensation to rearchitect the entire plugin? I’m starting to question whether this is worth my time and energy now.
I appreciate both @hanh and @1337bytes explaining their thinking here.
It seems Hanh is optimising for the simplest BTCPay implementation today: if Zkool already exposes GraphQL, connect to it directly from C#.
1337bytes is optimising for a broader wallet/payment-processor boundary: BTCPay talks to a stable wallet interface, while the backend can change underneath it.
That second point may become more useful than when the grant was first proposed. zecd now supports multiple wallets and watch-only UFVKs behind a Bitcoin-style RPC, and Zallet is also developing as a future wallet backend. A stable boundary could make moving from Zkool to zecd, and later possibly Zallet, much less disruptive for merchants.
For the current grant, I think the cleanest approach is simply to judge it against what was approved by ZCG at the start. If the specified code is delivered, pay the milestone. i.e. the approved RPC layer, multi-account support, mempool notifications, and the plugin changes needed to use them - not a new direct C#/GraphQL rewrite.
Then ZCG could separately fund a security/code audit of the completed integration and use that, together with what has been learned here, to decide the longer-term architecture.
I don’t think Hanh and 1337bytes are necessarily trying to achieve opposing things: one is emphasising simplicity, the other avoiding longer-term backend lock-in.
Hope I haven’t misunderstand anything. Appreciate the work you guys are doing to improve e-comm integration with existing merchant sites - this is an important prong for Zcash adoption.
Well, if it is in the grant, then you definitely should be compensated for your work. Too bad I missed it back then.
But moving forward, this plugin is getting messier. For context, @vaspholdings, when the plugin was originally written, there was no light wallet server (we only had zcashd). I wrote a small lightwallet server (zcash-walletd) and adapted the Monero plugin (which is single-store). Then BTCPayServer dev decided to kick out all altcoins from the main codebase into plugins. They defined an API (single & multistore). Now we have a few lightwallet options: Zkool/GraphQL, zecd (zcashd). Regardless of which one is used, there is no good reason for zcash-walletd anymore. IMO, we should leverage the multistore API and make the Zcash plugin directly multistore, 0conf and talk to either zkool or zecd. Instead, we are keeping the obsolete plugin design and trying to unravel it in an external server.
Again, too bad I missed it. I think this would have been easier to do and more robust.
Thanks @hanh, that makes the slightly opaque history of the plugin, as it began in 2021, clearer to me.
The two approaches do seem closer than they first appeared. @1337bytes has already moved confirmation checking into the BTCPay Server plugin, and has multi-store and mempool notifications working locally.
So perhaps the sensible longer-term direction is to keep that logic in the BTCPay Server plugin, with a small common wallet interface underneath it for Zkool, zecd and eventually Zallet.
But finish off the current approved work first, then work out whether the old zcash-walletd pattern - now represented by zkool-walletd - adds any value to keep longer term?