← Book map

Chapter 06 · Tabs

Flags are the payment policy

An invoice is not just an amount. It is a set of permissions — any amount, any destination, conversion, routing — encoded as flags.

Invoice — the flags decide what the wallet may do An invoice carries amount, destination, currency, expiry, slippage, accepted systems and a tag, with flags that relax or constrain the payment. amount (BN base10) destination (PKH or ID) requestedCurrencyId expiryHeight maxEstimatedSlippage acceptedSystems[] acceptsAnyAmount acceptsAnyDestination acceptsConversion acceptsNonVerusSystems expires isPreconvert / isTagged Destination is omitted entirely when acceptsAnyDestination is on.

FIGURE 6.1 · VerusPayInvoiceDetails, as wired by the form.

Signed or not — a real choice

Invoice is the only tab where signed is optional. An unsigned invoice is a payment request anyone can read; a signed one proves which identity asked. The route branches on it and only calls requireString(payload.signingId) when signing.

Building the details

destination = acceptsAnyDestination ? undefined :
  new TransferDestination({
    type: destinationType === "id" ? DEST_ID : DEST_PKH,
    destinationBytes: fromBase58Check(address).hash
  });

amount = acceptsAnyAmount ? undefined : new BN(amountString, 10);   // must be > 0

details.setFlags({
  acceptsAnyAmount, acceptsAnyDestination, acceptsConversion,
  expires, acceptsNonVerusSystems, isTestnet, isPreconvert, isTagged
});

setFlags() is where most invoice bugs live: the field is set from the flags, not the other way round. If you pass amount but forget acceptsAnyAmount: false (or the reverse), the serialised invoice will disagree with the form.

Flag meanings worth internalising

FlagWhat it permits
acceptsAnyAmountPayer chooses the amount — no amount field serialised
acceptsAnyDestinationPayer chooses where to send — no destination serialised
acceptsConversionPayment may be converted through another currency, bounded by slippage
acceptsNonVerusSystemsPayment may route through listed PBaaS systems
expiresexpiryHeight is enforced
isPreconvertPre-conversion semantics
isTaggedAn invoice tag identifies the payment
Two flags are effectively permissions: "any amount" and "any destination". A wallet UI that shows them is telling the user they are handing over choice, not just convenience.

Reading the code

src/routes/requests/invoice.ts
  buildInvoiceRequest()   # destination, amount, flags, accepted systems
  generateInvoiceQr()     # signed branch + QR