Skip to content

Latest commit

 

History

History
95 lines (79 loc) · 4.89 KB

File metadata and controls

95 lines (79 loc) · 4.89 KB

walletnotify reference — push payments from your Core node to your backend

The recommended integration. Your wallets run on servers you control (DigiByte / Bitcoin / Litecoin Core, encrypted with your passphrase). On each relevant transaction the node pushes a verified payment to your backend over TLS with a shared secret. No wallet — and no watcher — ever runs on the backend side. The backend only ever stores public addresses and fulfills orders.

   YOUR NODE SERVER (per coin)                             YOUR BACKEND
 ┌───────────────────────────┐    walletnotify %s        ┌────────────────────────┐
 │ DigiByte/Bitcoin/Litecoin │──► walletnotify.sh ──┐     │ payment-ingest endpoint│
 │ Core (localhost RPC,      │    blocknotify %s    ├──►──┤  (shared secret)       │
 │ encrypted, your keys)     │──► blocknotify.sh ───┘ TLS │  mark invoice paid     │
 │                           │    (cron) refill-dd ─────► │  dd-pool-refill        │
 └───────────────────────────┘                           └────────────────────────┘
        keys never leave your server           the backend never holds keys / a wallet

How it works

  1. walletnotify (walletnotify=…/walletnotify.sh %s) fires on every wallet tx. The script reads the tx's receive outputs from the local RPC and POSTs each {asset, network, address, txid, vout, amount, confirmations} to your INGEST_URL. The backend matches the address to the open invoice (addresses are unique per invoice) and records the payment.
  2. blocknotify (blocknotify=…/blocknotify.sh %s) fires on every new block and re-reports recent receives so their confirmations advance to the threshold — then the backend marks the invoice paid (idempotently). DigiDollar note: walletnotify is not guaranteed to fire on a DigiDollar receive (0-sat P2TR outputs can fail the IsMine gate) — the blocknotify poll of listdigidollarunspent is the authoritative DigiDollar detection path.
  3. DigiDollar only: because DigiDollar has no watch-only model, the node also runs refill-dd-pool.mjs on a cron to push fresh getdigidollaraddress addresses (public only) into your backend's address pool.

The risky logic (amount/confirmation parsing, integer base units) lives in the unit-tested @blockindex/crypto-payments library; these scripts are thin I/O.

Node config

# digibyte.conf (DigiByte + DigiDollar) — also bitcoin.conf / litecoin.conf
server=1
txindex=1                 # MANDATORY for DigiDollar
digidollar=1              # DigiByte only
rpcbind=127.0.0.1         # localhost ONLY — RPC never faces the internet
rpcauth=...
walletnotify=/opt/merchant/walletnotify.sh %s
blocknotify=/opt/merchant/blocknotify.sh %s

Bitcoin/Litecoin Core use the identical walletnotify/blocknotify options.

Install (per coin server)

npm install @blockindex/crypto-payments
cp lib.mjs walletnotify.mjs blocknotify.mjs refill-dd-pool.mjs walletnotify.sh blocknotify.sh /opt/merchant/
chmod +x /opt/merchant/*.sh
cp .env.example /opt/merchant/.env   # then fill it in and restart the node

See .env.example for every variable. The short version:

CRYPTO_ASSET=DIGIDOLLAR           # or BTC | LTC | DGB  (one per coin daemon)
CRYPTO_NETWORK=mainnet            # mainnet | testnet | regtest
CORE_RPC_URL=http://127.0.0.1:14022
CORE_RPC_USER=...
CORE_RPC_PASSWORD=...
CORE_WALLET=dd_hot                # wallet name if multi-wallet
INGEST_URL=https://example.com/api/crypto-payment-ingest
INGEST_SECRET=<long random shared secret, also set on the backend>
DD_REFILL_URL=https://example.com/api/crypto-dd-pool-refill      # DigiDollar only
DD_REFILL_SECRET=<a DIFFERENT long random secret>                # DigiDollar only

DigiDollar pool cron:

*/5 * * * * cd /opt/merchant && CRYPTO_ASSET=DIGIDOLLAR node refill-dd-pool.mjs >> /var/log/dd-pool.log 2>&1

Security

  • Node RPC bound to 127.0.0.1; never internet-exposed. Keys never leave your server.
  • Transport is HTTPS/TLS; requests carry the x-crypto-ingest-secret shared secret, verified (constant-time) before any side effect.
  • Only public addresses + amounts + confirmations are ever sent — never keys.
  • Use a separate DD_REFILL_SECRET for the pool refill: whoever holds the refill secret can inject attacker-owned addresses and capture customer payments. Audit the pool periodically: every unused address must be ismine on the hot wallet.
  • The backend re-validates the reported amount against the invoice and credits only at the required confirmation depth, idempotently by (asset,network,txid,vout).