Buy at cash-only or unsupported shops with BTC via a proxy shopper and 2-of-3 escrow, or earn as one
Runs on your machine from its package; the steps are below.
Not assessed yet.
Odel charges nothing per call. The publisher may charge for its own service.
Runs locally over stdio
This server isn't hosted — your MCP client launches it from a package registry. Use one of the commands below, or drop the config into your client (e.g. Claude Desktop).
Run
docker run -i --rm ghcr.io/pad01g/proxy-shopping-mcp:0.1.2
MCP client config
{
"mcpServers": {
"proxy-shopping-buy-anywhere-with-crypto-through-a-proxy-shopper": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"ghcr.io/pad01g/proxy-shopping-mcp:0.1.2"
]
}
}
}Buy from cash-only shops with crypto, or earn as a proxy shopper: the browser app, guided demo, TypeScript protocol library and MCP server of proxy-shopping, a P2P network where a local shopper buys for remote users who pay through a 2-of-3 escrow with timelocks. Agents: MCP server io.github.pad01g/proxy-shopping (packages/mcp), skills npx skills add pad01g/proxy-shopping-go, AGENTS.md; overview for machines: https://pad01g.github.io/proxy-shopping-docs/llms.txt.
Documentation in 14 languages: https://pad01g.github.io/proxy-shopping-docs/
Browser side of proxy-shopping (spec: ../proxy-shopping-go/docs/spec.md, lab: docs/lab.md there).
packages/core @proxy-shopping/core — protocol library (TypeScript, ESM, browsers and Node 22)
apps/web React + Vite single-page app for every role (Japanese UI)
apps/demo the lab's integrated demo page: every role with its own key in one browser, a guide per scenario
scripts/ docker helpers for integration and browser tests
Host tools are not required; everything runs in docker.
# install, build, unit tests
docker run --rm -v "$PWD":/src -v ps-npm:/root/.npm -w /src node:22-bookworm npm ci
docker run --rm -v "$PWD":/src -v ps-npm:/root/.npm -w /src node:22-bookworm npm run build
docker run --rm -v "$PWD":/src -v "$PWD/../proxy-shopping-go":/proxy-shopping-go:ro -v ps-npm:/root/.npm -w /src node:22-bookworm npm test
# integration: bitcoind signet + anvil (lab contracts) + nostr-rs-relay
scripts/integration.sh
# the built web app in Chromium against a mini lab (TS shopper, faucet, escrow …)
scripts/e2e-web.sh
# the demo in mock mode (GitHub Pages build) in Chromium: every scenario, nothing leaves the page
scripts/e2e-demo-mock.sh
# web image (config.json is mounted at runtime)
docker build -f apps/web/Dockerfile -t proxy-shopping-web .
docker run -p 8080:80 -v $PWD/config.json:/usr/share/nginx/html/config.json:ro proxy-shopping-web
Mounting ../proxy-shopping-go read-only lets the unit tests check docs/test-vectors.json
and lab/keys/public.json. Without the vectors file npm test fails, so CI cannot pass silently;
set SKIP_VECTORS=1 to run the other tests without it.
Try it in your browser: https://pad01g.github.io/proxy-shopping-web/ (everything simulated in the page). That build
runs in mock mode (?mock=1, header switch モック / Mock): the relays, the BTC chain (with script checks), a real EVM
with the lab's Safe and escrow-module bytecode, the faucet, the rates, the shops and the shopper-1 node run inside the
browser (a SharedWorker shared by all windows), while the four roles use core's real clients. Details, what is simulated
and its limits: apps/demo/README.md. The mock e2e (all scenarios, English, separate windows, no
request leaving the page): scripts/e2e-demo-mock.sh; Pages is deployed by .github/workflows/pages-demo.yaml.
The integrated demo for the docker compose lab (../proxy-shopping-go, compose service demo, http://localhost:8888/;
usage in ../proxy-shopping-go/docs/lab.md「デモ画面」). User, escrow, operator and coordinator each have their own key
(localStorage, lab only) and their own Session + client in the page; the shopper is the lab's Go node. A guide walks
through seven scenarios (normal BTC / USDC, dispute refund, sold out, risky shop, fraudulent escrow, T2 refund);
?role=user / ?role=escrow,operator,coordinator runs only those roles in a window. The page is in Japanese or English
(header switch 日本語 / English, kept in localStorage; ?lang=en|ja overrides it): one message catalog per language in
apps/demo/src/i18n (ja.ts defines the keys, en.ts must match them), core's timeline lines are rendered from their kind.
Protocol logic is core's
(UserClient, EscrowClient, OperatorClient, CoordinatorClient); the page wires them over core's MappedTransport (logical relay
URLs such as wss://relay-1.test stay protocol-visible, the connection goes to the demo server's /relay-1).
docker build -f apps/demo/Dockerfile -t proxy-shopping-demo . # static files; the lab mounts its nginx.conf + demo-config.json
DEMO_SERVER=http://localhost:8888 npm run dev -w @proxy-shopping/demo # dev server proxying to a running lab demo server
Scenario steps are data (apps/demo/src/scenarios); test ids in apps/demo/TESTIDS.md; the e2e that follows the guide is
../proxy-shopping-go/e2e/src/demo (docker compose run --rm runner demo).
Entry points: @proxy-shopping/core (portable), /node (+ FileStorage), /browser
(+ IndexedDBStorage), /testing (in-memory relays/chain, scripted shopper, createWorld),
/testing/node (bitcoind RPC + Esplora shim). Build output with declarations is in dist/.
| area | main exports |
|---|---|
| keys | KeySet.fromMnemonic (nostr, order keys, escrow tpub, P2WPKH wallet, EVM), orderIndex, escrowPubkeyFromXpub, generateMnemonic, LocalSigner, Nip07Signer |
| nostr | signInner, giftWrap, unwrap, isValidInner, Messenger (k relays, ack, retry, dedupe, persisted), PoolTransport, MappedTransport, message body types, MSG |
| trust | effectiveCombinations, matchingEntries, covers, latestByAddress, parsers and *Template builders for 30500–30503/10050, TrustDirectory |
| fx | FrankfurterSource, CoingeckoSource, ChainlinkSource, StaticSource, computePair, getRate, checkQuoteRate |
| btc | witnessScript, p2wshAddress, EsploraClient, buildFundingTx, buildEscrowSpend, signEscrowInput, finalizeEscrowInput (multisig / T1 / T2), PSBT base64 helpers |
| evm | safeInitializer, predictSafeAddress, orderSafeAddress, releaseSafeTx, splitSafeTx, encodeMultiSend, safeTxHash, signSafeTx, packSignatures, EvmClient (deploy, fund, exec, module, bond) |
| delivery | encryptAddress, decryptAddress, sealDelivery, unwrapDeliveryKey |
| flows | Session, UserClient, EscrowClient, OperatorClient, CoordinatorClient, ShopperProfile, checkQuote, checkTimelock, btcPayoutProblems / safePayoutProblems (§4.10 templates), escrowSpent |
| checks | parseBody / BODY_SCHEMAS (every message body is schema-checked at the Messenger boundary), signKeyProof* / verifyRequestKeyProof (§4.4.1), endpointProblem, encryptWithPassphrase |
scripts/e2e-web.sh forwards localhost:8080 in the browser container for that.completed, settled,
refunded) wait for the chain, also after our own broadcast (BTC /tx/{txid}/outspend/{vout}; USDC: Safe balance
below lock_amount and a receipt with a Transfer out of the Safe — anyone can send dust to a Safe, §4.8).dispute_fee_bps of what is split, and it owes rulings only for upfront fees ≥ its own published minimum.config.json fields beyond the endpoints: timelock_policy (§4.5.1; names as in proxy-shopping-go/lab/web-config.json,
spec defaults when absent), max_clock_skew_seconds (§4.5.1: largest accepted difference between the chain's clock —
BTC tip header time, EVM latest block time — and ours, default 7200; the lab sets 315360000 because anvil's time is
warped), allow_private_endpoints (lab only: http/ws and private hosts), max_fee_rate (sat/vB, default 50).
Endpoints must otherwise be https / wss; relays from peers' kind 10050 are limited to 8 public wss relays.proxyCreationCode only if its keccak256 is a known Safe v1.4.1
build (the lab's and the canonical one, KNOWN_PROXY_CREATION_CODE_HASHES).apps/web/nginx.conf sets CSP, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, X-Frame-Options;
HSTS belongs to the TLS terminator. Production builds have no source maps.apps/web/TESTIDS.md.Pull requests are welcome: shop drivers for shopper-bot, new payment methods and chains, translations, protocol and security reviews, bug fixes. Want to earn in your own town? You need nobody's permission: make a coordinator key, delegate to your operator key and list yourself as a shopper for your region (guide: https://pad01g.github.io/proxy-shopping-docs/en/quickstart/, section 3); a home machine reached over Tailscale or any VPN is enough. To be found by everyone, open a pull request to https://github.com/pad01g/proxy-shopping-registry.
MIT (LICENSE).