Skip to main content

Bond Purchase Payments

This chapter details the fiat flow and lifecycle for bond purchases created from marketplace deals. The Core Payment Service acts as the central orchestrator ensuring that buyer payment collection, seller payout, and on-chain Delivery-versus-Payment (DvP) are executed in the correct order.

Business Flow

  1. Transaction Initialization:

    • When an offer is accepted directly, the Core Payment Service consumes the DEAL_CREATED Kafka event and creates a bond_purchase_payment record with an initial state of CREATED.
    • When a counter-offer is accepted, the Core Payment Service consumes the accepted COUNTER_OFFER_RESOLVED Kafka event and creates the same type of payment record.
    • IBAN Resolution & AML/KYC: The Payment Service queries the Company Service and Registry Service to fetch and cache the fiat IBANs and crypto wallet addresses for both the buyer and the seller. This ensures deterministic data for the duration of the payment lifecycle.
    AML/KYC Validation

    While resolving the payment details, the transaction undergoes strict Anti-Money Laundering (AML) checks in the background. Initially, the Validator Backend performs a KYC/AML screening on both the buyer and seller. If successful, the results are forwarded to the External PSP, which conducts its own final internal AML screening before the fiat transaction is fully cleared.

  2. Fiat Collection (Buyer Payment):

    • The platform instructs the buyer to transfer funds to the PSP (Payment Service Provider).
    • BondPurchaseCreateChecker processes CREATED payments, creates the PSP-side bond payment, stores the sender payment reference, and moves the payment to BUYER_PAYMENT_AUTHORISED.
    • The PSP confirms the buyer's incoming payment through the external callback handled by the Core Payment Service.
    • The payment state transitions to BUYER_PAID.
  3. On-chain Settlement (DvP):

    • BondPurchaseBuyerPaidChecker processes BUYER_PAID payments and calls resolvePayment(dealId, true) on the marketplace smart contract.
    • This confirms on-chain that the buyer side of the deal has been funded.
    • After a successful on-chain confirmation, the payment state transitions to DEAL_PAID.
  4. Fiat Distribution (Seller Receipt):

    • BondPurchaseDealPaidChecker processes DEAL_PAID payments and validates the seller payout with the PSP.
    • After the outgoing seller payment is submitted to the PSP, the payment state transitions to SELLER_PAYMENT_AUTHORISED.
    • The PSP confirms the seller payout through the external callback handled by the Core Payment Service, moving the payment to SELLER_PAID.
    • BondPurchaseSellerPaidChecker then calls settleDeal(dealId) on-chain and moves the payment to the terminal state DEAL_SETTLED.

State Machine & Polling

Because the platform integrates asynchronous fiat gateways and blockchain networks, the Core Payment Service combines PSP callbacks with scheduled processing jobs:

  • BondPurchaseCreateChecker: Processes CREATED payments, resolves fees, and creates the PSP payment every 50 seconds.
  • BondPurchaseBuyerPaidChecker: Processes BUYER_PAID payments and calls resolvePayment(dealId, true) every 60 seconds.
  • BondPurchaseDealPaidChecker: Processes DEAL_PAID payments and validates the seller payout with the PSP every 60 seconds.
  • BondPurchaseSellerPaidChecker: Processes SELLER_PAID payments and calls settleDeal(dealId) every 60 seconds.
  • BondPurchasePendingExpiryChecker: Resolves expired pending deals as unpaid by calling resolvePayment(dealId, false).

Deal Settlement Handling

Final deal settlement starts after the PSP confirms the seller payout through the paymentsSent callback. The Core Payment Service matches the callback by receiverPaymentReference, updates the existing BondPurchasePayment to SELLER_PAID, and stores the payment status history.

The deal is not marked as locally settled at callback time. BondPurchaseSellerPaidChecker later processes payments in SELLER_PAID, calls settleDeal(dealId) on-chain, and updates the local payment to DEAL_SETTLED only after the on-chain settlement succeeds. If settlement fails because the deal has an invalid on-chain status, the dispute period has not expired, or another unrecoverable chain error occurs, the payment remains in SELLER_PAID for retry or manual investigation.

State Diagram

Sequence Diagram