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
-
Transaction Initialization:
- When an offer is accepted directly, the Core Payment Service consumes the
DEAL_CREATEDKafka event and creates abond_purchase_paymentrecord with an initial state ofCREATED. - When a counter-offer is accepted, the Core Payment Service consumes the accepted
COUNTER_OFFER_RESOLVEDKafka 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 ValidationWhile 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.
- When an offer is accepted directly, the Core Payment Service consumes the
-
Fiat Collection (Buyer Payment):
- The platform instructs the buyer to transfer funds to the PSP (Payment Service Provider).
BondPurchaseCreateCheckerprocessesCREATEDpayments, creates the PSP-side bond payment, stores the sender payment reference, and moves the payment toBUYER_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.
-
On-chain Settlement (DvP):
BondPurchaseBuyerPaidCheckerprocessesBUYER_PAIDpayments and callsresolvePayment(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.
-
Fiat Distribution (Seller Receipt):
BondPurchaseDealPaidCheckerprocessesDEAL_PAIDpayments 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. BondPurchaseSellerPaidCheckerthen callssettleDeal(dealId)on-chain and moves the payment to the terminal stateDEAL_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: ProcessesCREATEDpayments, resolves fees, and creates the PSP payment every 50 seconds.BondPurchaseBuyerPaidChecker: ProcessesBUYER_PAIDpayments and callsresolvePayment(dealId, true)every 60 seconds.BondPurchaseDealPaidChecker: ProcessesDEAL_PAIDpayments and validates the seller payout with the PSP every 60 seconds.BondPurchaseSellerPaidChecker: ProcessesSELLER_PAIDpayments and callssettleDeal(dealId)every 60 seconds.BondPurchasePendingExpiryChecker: Resolves expired pending deals as unpaid by callingresolvePayment(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.