Skip to content
    hazBasehazBaseDocs
    IMPLEMENTATION PATTERNS

    Debt & asset finance

    Model distinct rights and connect repayment, distributions and records.

    All implementation patterns
    EXAMPLE

    Issue equipment-finance positions and reconcile repayments

    Track positions in an equipment business separately when maturity or payment terms differ. Map BondToken classId to a category of terms and nonceId to an issuance series or maturity, then record each investor’s units.

    Build a view connecting agreement terms, issuance series, investor holdings, payment schedules and actual receipts.

    Architecture and responsibilities

    1. Agreements and investors

      Manage agreement originals, investor eligibility and payment schedules.

      Application API / DB
    2. Positions and holdings

      Track issuance and holdings for each classId and nonceId pair.

      BondTokenHelper
    3. Payments and claims

      Reconcile bank transfers or connect token-based claim processing as appropriate.

      Bank integration / DebtManagerHelper
    4. Operations and reporting

      Store holdings at the record date and payment outcomes for reporting.

      Snapshots / Application ledger

    Example data model

    Map application records to the data managed by the chain or APIs. Field names and values below illustrate the application model for this architecture.

    Field and exampleStored inPurpose and mapping
    agreementId / termsVersionFIN-001 / v1Application DBIdentify principal, dates, equipment and the agreement version.
    classId20Chain and DB mappingCategory of rights or terms, defined by the application.
    nonceId202709Chain and DB mappingAn issuance series within a class, distinct from signature replay-protection nonces.
    investor / unitsinvestorWallet / 10ChainHoldings are integer units. The agreement defines the amount and currency per unit.
    paymentId / recordDatePAY-2027-09 / timestampApplication DBIdentify the payment and record date, retaining the snapshot ID or block used.
    bankReference / transactionHashbank-ref / 0x…Application DBRecord bank transfers and chain transactions as separate evidence.

    Processing flow

    1. Map terms to a class and series

      Map FIN-001 to classId 20 and its series to nonceId 202709. Create both identifiers and include only public metadata on chain.

      createClass(classId, data) → createNonce(classId, nonceId, data)
    2. Issue after eligibility and funding checks

      Check identity, agreement and funding in the application. Configure any required allowlist, then issue 10 units. Token issuance does not itself verify a bank deposit.

      issue(investor, classId, nonceId, 10n)
    3. Fix holdings at the record date

      Associate payment entitlement with holdings at the contractual record date, not the current balance at payment time. BondToken snapshots are created when called; they cannot retroactively create a snapshot for an arbitrary date.

      snapshot() → balanceOfAt(holder, classId, nonceId, snapshotId)
    4. Connect the payment path

      For bank transfers, reconcile amounts and receipts in the application ledger. With DebtManager, configure BondToken, principal and coupon tokens, permissions and schedules, then fund the coupon using payCoupon.

      DebtManager: createTranche → addCouponSchedule → payCoupon → claimCoupon
    5. Reconcile redemption and records

      Reconcile principal repayment with retiring units. BondToken redeem burns units; linking that action to a payout requires a payment workflow such as DebtManager.

      BondToken.redeem / DebtManager.redeemAtMaturity

    Before using the code

    • Provide an initialized BondToken, an existing classId and nonceId, and a signer with MINTER_ROLE.
    • Pass position units as bigint. Distinguish these units from ERC-20 amounts with decimals.
    • Complete eligibility, agreement and funding checks, including any required allowlisting, before calling.
    Install
    npm install --save-exact @hazbase/kit@0.9.0 ethers@6.16.0

    The TypeScript functions below are called from your application with the appropriate connections, permissions and data. Integrate the UI, persistence and recovery using the architecture above.

    Allocate a position in a specific series

    Use classId: 20n, nonceId: 202709n and units: 10n. agreementId is your application’s agreement ID, included in the result for ledger persistence.

    pattern-finance.ts
    import { BondTokenHelper } from '@hazbase/kit';
    type Signer = Parameters<typeof BondTokenHelper.deploy>[1];
    
    export async function allocateBond(input: {
      agreementId: string;
      tokenAddress: string;
      classId: bigint;
      nonceId: bigint;
      investor: string;
      units: bigint;
      issuer: Signer;
    }) {
      // The class and nonce must already exist; issuer needs MINTER_ROLE.
      if (input.units <= 0n) throw new Error('Units must be positive.');
      const bond = BondTokenHelper.attach(input.tokenAddress, input.issuer);
      const receipt = await bond.issue(
        input.investor, input.classId, input.nonceId, input.units,
      );
      const balance = await bond.balanceOf(
        input.investor, input.classId, input.nonceId,
      );
    
      return {
        agreementId: input.agreementId,
        classId: input.classId.toString(),
        nonceId: input.nonceId.toString(),
        investor: input.investor,
        issuedUnits: input.units.toString(),
        balance: balance.toString(),
        transactionHash: receipt.hash,
      };
    }
    
    Download the example

    Result and application integration

    The investor’s balance for the class and nonce increases and a transaction hash is returned. This operation does not move money. Reconcile funding confirmation and issuance using the agreement ID.

    Implementation considerations

    Coupon record dates

    DebtManager payCoupon uses a snapshot taken at execution. If entitlement belongs to holders at an earlier record date, use a workflow matching that record rather than distributing to current holders.

    Currencies, decimals and rounding

    Distinguish principal currency, coupon-token decimals and amount per unit. Align rounding and residual handling between the ledger and contract calculations.

    Permissions and funding

    DebtManager needs the necessary BondToken permissions plus payment-token balances and allowances. Keep insufficient-funding and overdue states distinct from paid.

    Extending the architecture

    Fixed routes versus holder distributions

    Splitter routes funds to configured recipients and ratios; it does not enumerate token holders for dividends. Separate fixed counterparty splits from record-date holder distributions.

    Working with Fund Ops

    Fund Ops serves fund operators investing in RWAs, particularly asset finance. Map its scope to your own agreement and investor-management systems when integrating.