Class VoucherService

java.lang.Object
xyz.tcheeric.cashu.voucher.app.VoucherService

public class VoucherService extends Object
Main voucher service that orchestrates use cases.

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 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

      public IssueVoucherResponse issue(@NonNull @NonNull IssueVoucherRequest request)
      Issues a new voucher.

      This method performs the following operations:

      1. Calculates expiry timestamp (if specified)
      2. Creates a VoucherSecret with the provided parameters
      3. Signs the voucher with the mint's private key
      4. Publishes the voucher to the public ledger with ISSUED status
      5. Serializes to Cashu token format
      6. 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 invalid
      RuntimeException - if signing or publishing fails
    • queryStatus

      public Optional<VoucherStatus> queryStatus(@NonNull @NonNull String voucherId)
      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 blank
      RuntimeException - 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 invalid
      RuntimeException - 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 invalid
      RuntimeException - if backup fails
    • restore

      public List<SignedVoucher> restore(@NonNull @NonNull String userPrivateKey)
      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 invalid
      RuntimeException - if restore fails
    • exists

      public boolean exists(@NonNull @NonNull String voucherId)
      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 blank
      RuntimeException - 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 vreqA prefix 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:
      • VoucherPaymentRequest