Skip to content
    hazBasehazBaseDocs
    IMPLEMENTATION PATTERNS

    Physical assets & inventory

    Connect asset identity and rights to issuance, transfers and holdings.

    All implementation patterns
    EXAMPLE

    Issue equipment-related rights and track their holders

    Represent contractual rights associated with delivery robot A-001 as 1,000 units and allocate 10 to a partner. Keep equipment information in the asset register and manage issued units and holdings through a token.

    Look up an asset ID to display its token, current holders and balances, and allocation and transfer history in one interface.

    Architecture and responsibilities

    1. Asset interface

      Display equipment, agreements, recipients and quantities.

      Web UI
    2. Application API and register

      Map asset IDs to tokens and manage permissions and operation IDs.

      Application API / DB
    3. Issuance and transfers

      Enforce the issuance cap, track balances and execute permitted transfers.

      FlexibleTokenHelper
    4. History synchronization

      Index confirmed transactions and link them to operating and inspection records.

      Transaction receipts / Events

    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
    assetIdROBOT-A-001Application DBStable equipment ID mapped to the serial number or register entry.
    agreementIdAGR-2027-001Application DBAgreement and version defining the represented right. Store originals and personal data under access control.
    chainId + tokenAddresschainId / 0x…DB and chainAn address identifies different contracts on different chains. Always store both.
    cap / decimals1000 / 0ChainThis example uses whole units. Configure the issuance cap and decimals at initialization.
    holder / balancepartnerWallet / 10ChainThe chain is authoritative for balances. DB listings are indexed views.
    operationId / transactionHashALLOC-001 / 0x…Application DBTrack accepted, submitted and confirmed states to avoid duplicate issuance on retries.

    Processing flow

    1. Register the asset and right

      Register A-001 and agreement AGR-2027-001. With one contract per asset, the token balance represents units of the right associated with that equipment.

      Application DB: assetId → agreementId → tokenAddress
    2. Initialize the token

      Prepare FlexibleToken with a cap of 1,000 and zero decimals. Grant the issuer MINTER_ROLE and configure transferability and any required allowlist.

      FlexibleTokenHelper.deploy / attach
    3. Allocate 10 units

      Save the allocation request before minting. Associate the confirmed receipt with the request and read the balance. Use transfer with the holder’s signer when moving existing units.

      mint(recipient, amount) → balanceOf(recipient)
    4. Update the holder view

      Index Transfer events using chainId, transactionHash and logIndex as a unique key. Periodically reconcile the display database with on-chain balances.

      Transfer events / balanceOf
    5. Add operating records

      Link hours, inspections and faults by assetId. Track rights transfers separately from physical delivery, with physical verification handled by the operating system.

      Application DB: operating_records.assetId

    Before using the code

    • Provide an initialized FlexibleToken address and an issuer signer connected to its chain.
    • Use a cap of 1,000 and zero decimals for this example. Pass display quantities as strings in units.
    • Check MINTER_ROLE, pause state and any eligibility conditions for the recipient.
    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 units with the equipment ID

    Call allocateAsset with assetId, tokenAddress, recipient, units: "10" and issuer. Use its returned values to persist the result in your application API.

    pattern-assets.ts
    import { FlexibleTokenHelper } from '@hazbase/kit';
    import { parseUnits } from 'ethers';
    type Signer = Parameters<typeof FlexibleTokenHelper.deploy>[1];
    
    export async function allocateAsset(input: {
      assetId: string;
      tokenAddress: string;
      recipient: string;
      units: string;
      issuer: Signer;
    }) {
      if (!input.issuer.provider) throw new Error('A connected signer is required.');
      // Requires an initialized token and a signer with MINTER_ROLE.
      const token = FlexibleTokenHelper.attach(input.tokenAddress, input.issuer);
      const amount = parseUnits(input.units, await token.decimals());
      if (amount <= 0n) throw new Error('Units must be positive.');
    
      const receipt = await token.mint(input.recipient, amount);
      const balance = await token.balanceOf(input.recipient);
      const network = await input.issuer.provider.getNetwork();
    
      // Persist this mapping in your asset register after confirmation.
      return {
        assetId: input.assetId,
        chainId: network.chainId.toString(),
        tokenAddress: input.tokenAddress,
        holder: input.recipient,
        allocatedAtomic: amount.toString(),
        balanceAtomic: balance.toString(),
        transactionHash: receipt.hash,
        blockNumber: receipt.blockNumber,
      };
    }
    
    Download the example

    Result and application integration

    For a recipient starting at zero, balanceAtomic becomes "10". Save transactionHash and blockNumber in the operation history. Each mint creates additional units, so page reloads and retries must not call it unconditionally.

    Implementation considerations

    Quantity units

    Passing 10 directly to a token with 18 decimals does not represent 10 display units. The example reads decimals and converts using parseUnits.

    Database failure after a successful transaction

    The issuance remains on chain. Use a submission process that stores the operation ID and transaction hash before confirmation, then recover results from events.

    Different rights per asset

    Units of one token are fungible. Different equipment terms may require separate contracts; individually identified items can use a PrivilegeNFT-based design.

    Extending the architecture

    Inventory and custody

    Replace assetId with a storage lot and represent fungible goods as units. Reconcile warehouse delivery confirmation with token burning.

    Working with RWA Ops

    RWA Ops covers equipment definition, issuance, allocation and operating records together. Compare it with an API/SDK integration for custom interfaces and existing registers.