Class VoucherService
This service provides the primary business logic for voucher operations, coordinating between the domain layer (voucher creation, signing, validation) and the infrastructure layer (storage via ports).
Responsibilities
- Issue new vouchers (create, sign, publish to ledger)
- Query voucher status from the public ledger
- Update voucher status (state transitions)
- Orchestrate backup and restore operations
- Serialize vouchers to Cashu token format
Architecture
This service follows hexagonal architecture principles:
- Depends on ports (interfaces) not concrete implementations
- Uses domain entities (VoucherSecret, SignedVoucher)
- Returns DTOs for API boundaries
- Infrastructure-agnostic (no knowledge of Nostr, SQL, etc.)
Usage Example
// Setup (typically in Spring/Guice configuration)
VoucherLedgerPort ledger = new NostrVoucherLedgerRepository(...);
VoucherBackupPort backup = new NostrVoucherBackupRepository(...);
VoucherService service = new VoucherService(ledger, backup, privKey, pubKey);
// Issue a voucher
IssueVoucherRequest request = IssueVoucherRequest.builder()
.issuerId("merchant123")
.unit("sat")
.amount(10000L)
.expiresInDays(365)
.memo("Birthday gift")
.build();
IssueVoucherResponse response = service.issue(request);
SignedVoucher voucher = response.getVoucher();
System.out.println("Voucher ID: " + response.getVoucherId());
// To create a shareable token, use a wallet (e.g., cashu-client)
// that can swap proofs at the mint with the voucher as the secret.
// Query status
Optional<VoucherStatus> status = service.queryStatus(response.getVoucherId());
// Backup vouchers
service.backup(List.of(voucher), userNostrPrivateKey);
- See Also:
-
Constructor Summary
ConstructorsConstructorDescriptionVoucherService(@NonNull VoucherLedgerPort ledgerPort, @NonNull VoucherBackupPort backupPort, @NonNull String mintIssuerPrivateKey, @NonNull String mintIssuerPublicKey) Constructs a VoucherService with the required dependencies. -
Method Summary
Modifier and TypeMethodDescriptionvoidbackup(@NonNull List<SignedVoucher> vouchers, @NonNull String userPrivateKey) Backs up vouchers to private user storage.booleanChecks if a voucher exists in the public ledger.generatePaymentRequest(@NonNull GeneratePaymentRequestDTO dto) Generates a NUT-18V VoucherPaymentRequest for receiving voucher payments.issue(@NonNull IssueVoucherRequest request) Issues a new voucher.queryStatus(@NonNull String voucherId) Queries the current status of a voucher from the public ledger.Restores vouchers from private user storage.voidupdateStatus(@NonNull String voucherId, @NonNull VoucherStatus newStatus) Updates the status of a voucher in the public ledger.
-
Constructor Details
-
VoucherService
public VoucherService(@NonNull @NonNull VoucherLedgerPort ledgerPort, @NonNull @NonNull VoucherBackupPort backupPort, @NonNull @NonNull String mintIssuerPrivateKey, @NonNull @NonNull String mintIssuerPublicKey) Constructs a VoucherService with the required dependencies.- Parameters:
ledgerPort- the port for public ledger operations (must not be null)backupPort- the port for private backup operations (must not be null)mintIssuerPrivateKey- the mint's private key for signing vouchers (hex-encoded, must not be null)mintIssuerPublicKey- the mint's public key for voucher verification (hex-encoded, must not be null)
-
-
Method Details
-
issue
Issues a new voucher.This method performs the following operations:
- Calculates expiry timestamp (if specified)
- Creates a VoucherSecret with the provided parameters
- Signs the voucher with the mint's private key
- Publishes the voucher to the public ledger with ISSUED status
- Serializes to Cashu token format
- Returns response with voucher and token
- Parameters:
request- the voucher issuance request (must not be null)- Returns:
- the issuance response containing the voucher and token
- Throws:
IllegalArgumentException- if request parameters are invalidRuntimeException- if signing or publishing fails
-
queryStatus
Queries the current status of a voucher from the public ledger.- Parameters:
voucherId- the unique voucher identifier (must not be null or blank)- Returns:
- the current status, or empty if voucher not found in ledger
- Throws:
IllegalArgumentException- if voucherId is null or blankRuntimeException- if ledger query fails
-
updateStatus
public void updateStatus(@NonNull @NonNull String voucherId, @NonNull @NonNull VoucherStatus newStatus) Updates the status of a voucher in the public ledger.This method records a state transition in the ledger. Common transitions:
- ISSUED → REDEEMED
- ISSUED → REVOKED
- ISSUED → EXPIRED
- Parameters:
voucherId- the unique voucher identifier (must not be null or blank)newStatus- the new status to set (must not be null)- Throws:
IllegalArgumentException- if parameters are invalidRuntimeException- if ledger update fails
-
backup
public void backup(@NonNull @NonNull List<SignedVoucher> vouchers, @NonNull @NonNull String userPrivateKey) Backs up vouchers to private user storage.This method encrypts and stores the vouchers in a way that only the user can retrieve them using their private key.
- Parameters:
vouchers- the list of vouchers to backup (must not be null, can be empty)userPrivateKey- the user's private key for encryption (must not be null or blank)- Throws:
IllegalArgumentException- if parameters are invalidRuntimeException- if backup fails
-
restore
Restores vouchers from private user storage.This method retrieves and decrypts all voucher backups associated with the user's private key.
- Parameters:
userPrivateKey- the user's private key for decryption (must not be null or blank)- Returns:
- list of restored vouchers (never null, but may be empty)
- Throws:
IllegalArgumentException- if userPrivateKey is invalidRuntimeException- if restore fails
-
exists
Checks if a voucher exists in the public ledger.- Parameters:
voucherId- the unique voucher identifier (must not be null or blank)- Returns:
- true if the voucher exists in the ledger, false otherwise
- Throws:
IllegalArgumentException- if voucherId is null or blankRuntimeException- if ledger query fails
-
generatePaymentRequest
public GeneratePaymentRequestResponse generatePaymentRequest(@NonNull @NonNull GeneratePaymentRequestDTO dto) Generates a NUT-18V VoucherPaymentRequest for receiving voucher payments.This method creates an encoded payment request that can be:
- Displayed as a QR code at point-of-sale
- Shared via NFC, link, or message
- Used to initiate voucher redemption flow
The generated request uses the
vreqAprefix format and includes the issuer ID, amount, and configured transports.Usage Example
GeneratePaymentRequestDTO dto = GeneratePaymentRequestDTO.builder() .issuerId("merchant123") .amount(5000) .unit("sat") .description("Coffee purchase") .callbackUrl("https://merchant.com/api/redeem") .build(); GeneratePaymentRequestResponse response = voucherService.generatePaymentRequest(dto); String qrContent = response.getEncodedRequest();- Parameters:
dto- the payment request parameters (must not be null)- Returns:
- the response containing the encoded request and metadata
- Throws:
IllegalArgumentException- if required parameters are missing- See Also:
-