Invoice Engine
The InvoiceEngine is the core orchestrator of DeroPay. It coordinates invoice creation, payment monitoring, storage, and webhook dispatch.
Configuration
import { InvoiceEngine, SqliteInvoiceStore } from "dero-pay/server";
const engine = new InvoiceEngine({
// Required: DERO wallet RPC endpoint
walletRpcUrl: "http://127.0.0.1:10103/json_rpc",
// Required: DERO daemon RPC endpoint
daemonRpcUrl: "http://127.0.0.1:10102/json_rpc",
// Optional: RPC authentication
rpcAuth: { username: "", password: "" },
// Optional: webhook configuration
webhookUrl: "https://mystore.com/webhooks/dero",
webhookSecret: process.env.WEBHOOK_SECRET!,
webhookMaxRetries: 3,
// Optional: storage backend (defaults to MemoryInvoiceStore)
store: new SqliteInvoiceStore({ path: "./invoices.db" }),
// Optional: polling interval in ms (default: 5000)
pollIntervalMs: 5000,
// Optional: confirmations required (default: 3)
defaultRequiredConfirmations: 3,
// Optional: invoice expiry in seconds (default: 900 — 15 minutes)
defaultTtlSeconds: 900,
// Optional: escrow settings
enableEscrow: true,
escrowFeeBasisPoints: 250, // 2.5% platform fee
escrowBlockExpiration: 60, // blocks until expiry
});Lifecycle
// Start the engine (begins payment monitoring)
await engine.start();
// Create invoices
const invoice = await engine.createInvoice({
name: "Product Name",
description: "Product description",
amount: 500000, // atomic units (5 DERO)
metadata: { orderId: "ORD-123" }, // optional custom data
});
// Query invoice status
const status = await engine.getInvoice(invoice.id);
// Stop the engine
await engine.stop();Events
The engine emits events you can listen to:
engine.on("invoiceStatusChanged", (invoice, previousStatus) => {
// Fires on every status transition
});
engine.on("paymentDetected", (invoice, payment) => {
// Fires when a matching transaction is found (before full confirmation)
});
engine.on("paymentConfirmed", (invoice, payment) => {
// Fires when payment reaches required confirmation depth
});
engine.on("error", (error) => {
// Fires on engine errors (RPC failures, etc.)
});How Payment Detection Works
- When an invoice is created, DeroPay generates a unique payment ID and combines it with the merchant's DERO address into an integrated address
- The
PaymentMonitorpolls the wallet RPC for incoming transfers - Each transfer is checked for a matching payment ID
- When found, the amount is verified and confirmations are tracked
- Once the required confirmations are reached, the invoice is marked
completed
Integrated addresses are a DERO feature where a payment ID is embedded directly in the address. This means each invoice has a unique address, making payment matching deterministic.
Pricing Utilities
DeroPay includes helpers for converting between DERO and atomic units:
import { deroToAtomic, atomicToDero, formatDero, ATOMIC_UNITS_PER_DERO } from "dero-pay";
deroToAtomic("5.0"); // 5_000_000_000_000n (BigInt)
deroToAtomic("0.001"); // 1_000_000_000n
atomicToDero(5_000_000_000_000n); // "5.0"
formatDero(5_000_000_000_000n); // "5.000000000000 DERO"⚠️
DERO uses 12 decimal places (1 DERO = 10^12 atomic units). This is different from Ethereum's 18 decimals or Bitcoin's 8.