Skip to main content

Payment proofs

On a transparent chain, proving you paid someone means pointing at a transaction. On Epic there is nothing to point at, because the ledger holds blinded commitments with no sender, recipient or readable amount. Proof of payment therefore has to be constructed deliberately, at the time of the transfer.

A payment proof is that construct. It binds an amount, a sender and a recipient into evidence the sender can present later.

What it establishes

A payment proof shows that the holder of a particular recipient key acknowledged receiving a particular amount from a particular sender, as part of a specific transaction.

It does not show that goods were delivered, that the transaction confirmed, or that the recipient is who they claim to be outside the protocol. It is a cryptographic receipt, and the only copy is the one you keep, since nothing in the chain lets you reconstruct it.

Request it when you send

A proof cannot be produced after the fact. The recipient signs the proof message as part of their round of the exchange, so it has to be requested when the transfer starts.

epic-wallet send --request_payment_proof --proof_address <recipient_proof_address> -d <dest> 1.5

The recipient's proof address is required. When sending to a Tor address the wallet can supply it automatically; otherwise the recipient provides it from epic-wallet address.

Through the Owner API, set the payment proof fields on InitTxArgs when calling init_send_tx. Retrieval and verification are retrieve_payment_proof and verify_payment_proof.

Choose the transport accordingly

A payment proof is a V3 slate field, and epicbox converts every slate to V2, so a proof request does not survive an epicbox send (impls/src/adapters/epicbox.rs:251). Route a transfer that needs a proof over any other transport; the comparison has the matrix.

Verification

verify_payment_proof fails with an error if the transaction kernel named by the proof is not on the chain, or if either the recipient signature or the sender signature does not verify against the proof message. A successful call therefore means the proof is sound.

What it returns is a pair of booleans saying which side of the proof the calling wallet is on, (sender_mine, recipient_mine), each true when the wallet's own proof address matches that party (verify_payment_proof(), returned at libwallet/src/api_impl/owner.rs:1143). The JSON-RPC signature is at api/src/owner_rpc_s.rs:2161.

Next