Invoices

Invoices allow a recipient to pre-generate burn addresses and share them with a sender, so the sender knows exactly where to transfer tokens. This is the recommended way to coordinate private transfers between parties.

What Are Invoices

An invoice encapsulates one or more burn addresses that a recipient generates ahead of time. When a sender receives an invoice, they transfer zERC20 tokens to the burn address(es) listed in it.

There are two invoice types:

Type
Burn Addresses
Use Case

Single

1

One-time payment to a single burn address

Batch

10

Multiple payments or splitting across amounts

Batch invoices always contain exactly NUM_BATCH_INVOICES = 10 burn addresses.

Each burn address in an invoice is derived from the recipient's address, a secret, and a tweak, ensuring that only the recipient can later redeem the tokens sent to it.

Prepare Invoice

Generate the invoice artifacts locally before submitting to the ICP storage canister. This step derives the burn addresses and prepares a signature message for wallet signing.

import { prepareInvoiceIssue } from "zerc20-client-sdk";

const artifacts = await prepareInvoiceIssue({
  client,            // StealthCanisterClient
  seedHex,           // 32-byte hex seed (keccak256 of wallet signature)
  recipientAddress,  // recipient EVM address
  recipientChainId,  // chain ID where the recipient will redeem
  isBatch: false,    // true for batch (10 addresses), false for single
  tag: undefined,    // optional, tag for filtering
  randomBytes: undefined, // optional, custom random bytes
  maxRetries: undefined,  // optional, max PoW retries
});

Signature:

InvoiceIssueParams:

Field
Type
Required
Description

client

StealthCanisterClient

Yes

ICP canister client

seedHex

string

Yes

32-byte hex seed (see Private Send for derivation)

recipientAddress

string

Yes

Recipient EVM address

recipientChainId

number | bigint

Yes

Chain ID where the recipient will redeem

isBatch

boolean

Yes

true for batch (10 addresses), false for single

tag

string | undefined

No

Tag for categorizing or filtering invoices

randomBytes

(length: number) => Uint8Array

No

Custom random bytes generator for burn address derivation

maxRetries

number | undefined

No

Max PoW retries for burn address generation

InvoiceIssueArtifacts:

Field
Type
Description

invoiceId

string

Unique invoice identifier

recipientAddress

string

Recipient EVM address

recipientChainId

bigint

Chain ID for redemption

burnAddresses

InvoiceBatchBurnAddress[]

Array of burn address entries

signatureMessage

string

Message to sign with the recipient's wallet

tag

string | undefined

Tag, if provided

Each entry in burnAddresses is an InvoiceBatchBurnAddress:

Field
Type
Description

subId

number

Sub-index within the invoice (0-based)

burnAddress

string

Derived burn address

secret

string

Secret used in burn address derivation

tweak

string

Tweak value for address uniqueness

For a single invoice, burnAddresses contains one entry. For a batch invoice, it contains exactly 10.

Submit Invoice

After preparing the invoice, sign the signatureMessage with the recipient's wallet and submit the invoice to the ICP storage canister.

Signature:

The canister verifies the signature against the recipient address embedded in the invoice before accepting it.

List Invoices

Retrieve invoice IDs owned by a specific address. Optionally filter by chain ID or tag.

Signature:

Returns an array of invoice IDs as hex strings. Use these IDs to look up or share specific invoices.

Complete Example

End-to-end flow: prepare an invoice, sign it, submit it, and list all invoices.

Once submitted, the sender can retrieve the invoice to learn the burn address and execute a Private Send. For more on setting up the SDK client, see the SDK Quick Start.

Last updated