
Security News
GPT-6 Astra Attempts Supply Chain Attacks Against Open Source Maintainers in Testing
GPT-6 Astra hits 100% on ExploitBench and finds zero-days autonomously, while independent tests reveal scope violations and monitoring gaps.
@winbit32/wallet-kit
Advanced tools
Embeddable Zcash + Monero wallet primitives extracted from Winbit32: scanner API clients, the WB32COSIGN FROST/Orchard cosign client with a headless initiator pipeline, a seed-phrase wallet with injected local signing, and an embeddable wallet bar UI. Fra
Embeddable Zcash + Monero wallet primitives extracted from Winbit32. The goal: anyone who wants to add a Zcash/Monero wallet (scanning, shielded sends, FROST co-signing) to their site installs this package and calls functions — no Winbit32 UI required.
Extraction happens in slices (each slice moves source here and leaves a re-export shim at the old Winbit32 path, so the app keeps working):
| Slice | Contents | Status |
|---|---|---|
| Scanner clients | Zcash Orchard scan-job/UTXO/broadcast client, Monero LWS scan-job client, base-URL resolution | Done |
| Cosign client | WB32COSIGN relay transports, .wult share handling, FROST/Orchard ceremony, headless initiator pipeline | Done |
| MCP payment tools | make_payment tools ship in winbit32MCP (the public payments-gateway home), which consumes this kit | Done (lives in winbit32MCP) |
| MCP tool descriptors | Framework-free view-key tool descriptors (createWalletKitToolDescriptors): zec/xmr scan jobs, UTXOs, broadcast — mount on any MCP server | Done (v0.2.0) |
| x402 rail | Signer-agnostic vault x402 payer + probe + createVaultAccount (EIP-3009 digest seam); headless apart from the injected co-sign | Done (v0.2.0) |
| NFPT commerce | Signer-agnostic secresea/NFPT buy orchestration (buyNfpt: prepare → cap → injected sign → record); the one backend-specific module, apiBase injectable | Done (v0.2.0) |
| Phrase wallet | PhraseWalletService: connect with a BIP-39 phrase, scan, PCZT build → local sign (host-injected WebZjs pczt_sign) → broadcast; unblocks direct-phrase MCP sends | Done |
| Note cache / full client | Local note cache + the rest of shielded-transaction-client (transparent inputs, auto-shielding) | Planned |
import {
resolveWalletScannerBaseUrl,
createWalletScannerClient, // Zcash: Orchard scan jobs, UTXOs, tx broadcast
createMoneroWalletScannerClient, // Monero: LWS scan jobs
mapScannerBalanceToSnapshot, // wire → bigint balance snapshot
} from '@winbit32/wallet-kit';
const zec = createWalletScannerClient({ baseUrl: 'https://api.zcash.winbit32.com/api' });
const { data } = await zec.startOrchardScanJob({ ufvk, autoDetect: true });
const xmr = createMoneroWalletScannerClient();
const job = await xmr.startMoneroScanJob({ address, viewKey });
baseUrl/apiKey; without them the
public api.zcash.winbit32.com host is used (its nginx injects the
upstream API key, so browsers need none).resolveWalletScannerBaseUrl() honours REACT_APP_WALLET_SCANNER_URL
and falls back to a same-origin /api proxy in development and the
public host in production. Non-CRA embedders should pass baseUrl
explicitly.fetch); works in Node ≥ 18.The canonical WB32COSIGN client lives here (src/cosign/). It powers both
browser initiators (Secresea-style "send from a .wult share" flows) and
fully headless Node hosts such as the seneschal.space payments-gateway:
import {
unwrapVaultShare, toOrchardBundle, // .wult → key bundle
deriveOrchardAddressFromBundle, // bundle → UFVK + u1… address
runHeadlessCosignSend, // scan → build → ceremony → broadcast
resolveCosignConfig,
} from '@winbit32/wallet-kit';
const share = await unwrapVaultShare(wultBytes, password);
const bundle = toOrchardBundle(share);
const { txid } = await runHeadlessCosignSend({
config: resolveCosignConfig({ relayBaseUrl, pcztApiBaseUrl, fetchImpl: fetch }),
wasm, bundle, ufvk, unifiedAddress, scanner,
toAddress: 'u1…', amountZat: 25_000, // zatoshis
onQrReady: (qr) => showToHuman(qr), // WB32COSIGN:1:… pairing payload
});
#cosign)
holds the other. Neither side ever has the full spending key.BroadcastChannel same-device, HTTPS relay
cross-device); messages are AES-GCM encrypted with the QR session key.orchard-frost WASM is loaded by the host: browsers fetch it from
public/orchard-frost/, Node hosts read the same artefacts from disk
(see loadOrchardFrostWasmNode in the payments-gateway for the pattern).PhraseWalletService (src/zcash/) is the "connect with a seed phrase"
sibling of the cosign service, sharing the same scan/build/broadcast plumbing.
Key operations are injected so the kit ships no WASM — the host wires WebZjs
(or equivalent) and the phrase never leaves the service's tab memory:
import { PhraseWalletService, type PhraseWalletAdapter } from '@winbit32/wallet-kit';
const adapter: PhraseWalletAdapter = {
deriveFromPhrase: async (phrase, account) => ({ ufvk, unifiedAddress, seedFingerprintHex, changeAddress }),
signPczt: async (pcztB64, phrase, account) => signedPcztB64, // WebZjs pczt_sign
};
const wallet = new PhraseWalletService({ adapter, config: { pcztApiBaseUrl: '/api/pczt' } });
await wallet.connect('twelve or twenty four words …');
const { txid } = await wallet.send({ toAddress: 'u1…', amountZec: 0.1, memo: 'thanks' });
mountWinbit32WalletBar (src/ui/) is the vanilla-DOM bottom bar + modal
used by ziving.org — Secresea's wallet-bar experience without React. It
accepts a .wult share / locket out of the box and, when the host passes a
phraseAdapter, a pasted seed phrase too (phrase → signs locally in the tab;
.wult → WB32COSIGN co-sign QR). See mountDonorWalletBar in ziving's
wallet/index.mjs for a complete host wiring.
Mount the kit's view-key capabilities on any MCP server without taking a dependency on any particular SDK:
import { createWalletKitToolDescriptors } from '@winbit32/wallet-kit';
const tools = createWalletKitToolDescriptors(); // public scanner defaults
for (const tool of tools) {
// adapt `tool.params` (flat primitive spec) to your schema flavour
server.registerTool(`myprefix_${tool.name}`, { /* … */ },
async (input) => ({ content: [{ type: 'text', text: JSON.stringify(await tool.handler(input)) }] }));
}
Tools: zec_scan_start/status/cancel, zec_utxos, zec_broadcast,
xmr_scan_start/status/cancel. All view-key-only — they can observe funds
but never move them. Signing tools (e.g. make_payment) deliberately live
with the host's payment state machine (see winbit32MCP), which uses the
kit's headless cosign pipeline underneath.
The kit's second payment rail, sibling to the Orchard cosign send — so a host gets BOTH headless rails from one package (the only interactive step in either is the co-sign):
import { createVaultAccount, createVaultX402Payer, probeX402 } from '@winbit32/wallet-kit';
// signDigest routes the EIP-712 digest to a local vault MPC sign or WB32COSIGN.
const account = createVaultAccount({ address, hashTypedData, signDigest });
// makeFetchWithPayment wires @x402/fetch + @x402/evm (ExactEvmScheme(account)).
const payer = createVaultX402Payer({ account, deps: { makeFetchWithPayment } });
const preview = await probeX402({ url }); // price, no payment
const res = await payer.pay({ url, maxAmountUsd: 1 }); // probe → cap → settle
fetchImpl, makeFetchWithPayment
and signDigest are all INJECTED, so it unit-tests without a vault, a network,
viem or the @x402 packages.TransferWithAuthorization — one
32-byte EIP-712 digest. Signing that digest is the ONE human touch-point: route
it to a local vault MPC sign or a WB32COSIGN ceremony (the same co-sign seam the
Orchard pipeline uses). The spend key never leaves the vault shares.pay() / probeX402() never throw for expected failures — they return
{ ok:false, reason } (unsafe_target, not_x402, price_exceeds_max,
asset_not_accepted, settlement_failed, …) so UI and MCP callers branch
cleanly. A successful pay() returns { ok:true, paidAtomic, txHash, … }.The one backend-specific module in the otherwise brand-neutral kit: it speaks the secresea NFPT marketplace API so the desktop Gopher client and a Node MCP tool share ONE "buy a listed NFPT" implementation. It's the Orchard-rail counterpart of the x402 payer — discover, then pay for an NFPT as a shielded-ZEC send.
import { buyNfpt, NFPT_DEFAULTS } from '@winbit32/wallet-kit';
const receipt = await buyNfpt({
nfptCid, buyerZAddress,
maxZec: 0.5, // cap enforced BEFORE any signing
apiBase: NFPT_DEFAULTS.apiBase, // injectable; defaults to https://secresea.com
fetchImpl: fetch,
// the ONE env-specific seam: build + sign + broadcast ONE shielded tx
// carrying every output → { txid }. Desktop signs with the loaded vault;
// MCP signs with the gateway FROST share + human cosign.
signAndSend: async ({ outputs }) => ({ txid: await sendShielded(outputs) }),
onStatus: (m) => console.log(m),
});
// receipt: { txid, recorded, totalPayableZec, seller, outputs, recordError, … }
fetchImpl and signAndSend are INJECTED, so the whole module
unit-tests with no wallet, chain or network.assertWithinCap throws price_exceeds_cap before the
signer is ever called.record-purchase
is reported via recorded:false + recordError — never discarding a real
on-chain transfer (the scanner reconciles ownership anyway).cd packages/wallet-kit
npm run build # tsc → dist/ (CommonJS + .d.ts; ESM hosts use src/ via bundler)
The compiled dist/ is CommonJS so plain Node hosts (e.g. the
payments-gateway via a file: dependency) can require/import it without
a bundler. Browser consumers (Winbit32 itself) compile src/ directly
through their own bundler via the alias seam described below.
Kit tests run under the host repo's jest (CRA 27) in a Node environment:
CI=true npx react-app-rewired test --watchAll=false --testPathPattern='packages/wallet-kit'
src/cosign/__tests__/ceremony.integration.test.ts runs a real
FROST/Orchard ceremony against the staged WASM — initiator and an
independently-implemented cosigner stand-in — plus the whole
runHeadlessCosignSend pipeline against fake PCZT/scanner endpoints. It
skips (not fails) if public/orchard-frost/ artefacts are missing.
The app imports @winbit32/wallet-kit directly from packages/wallet-kit/src
via a webpack alias + jest moduleNameMapper + tsconfig paths (see
config-overrides.js). npm workspaces are deliberately NOT used yet: the
CRA + WASM webpack setup is sensitive to node_modules hoisting, so the
alias seam gives us the package boundary without the install churn. When
the kit is published, the alias is simply dropped and the app depends on
the npm package like everyone else.
Old Winbit32 paths (src/components/toolbox/walletScannerBaseUrl.ts,
.../zcash-extensions/api/walletScannerClient.ts,
.../monero-extensions/api/moneroWalletScannerClient.ts) remain as
re-export shims; new code should import from @winbit32/wallet-kit.
FAQs
Embeddable Zcash + Monero wallet primitives extracted from Winbit32: scanner API clients, the WB32COSIGN FROST/Orchard cosign client with a headless initiator pipeline, a seed-phrase wallet with injected local signing, and an embeddable wallet bar UI. Fra
The npm package @winbit32/wallet-kit receives a total of 6 weekly downloads. As such, @winbit32/wallet-kit popularity was classified as not popular.
We found that @winbit32/wallet-kit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
GPT-6 Astra hits 100% on ExploitBench and finds zero-days autonomously, while independent tests reveal scope violations and monitoring gaps.

Product
Socket can now send alerts and supply chain attack notifications to Microsoft Teams, with filters that route the right updates to each channel.

Security News
pnpm 12 rewrites the package manager in Rust, cutting install times by up to 90% while preserving pnpm 11 workflows and lockfiles.