This document describes how LiquiFact correlates internal API invoiceId identifiers with on-chain Stellar and Soroban data.
LiquiFact uses a unique invoiceId for every invoice uploaded to the platform. To ensure consistency between the off-chain database and the on-chain escrow state, a correlation strategy is required.
For escrows managed by Soroban smart contracts (e.g., LiquifactEscrow), the invoiceId is treated as contract-local state.
- Mechanism: The
invoiceIdis passed as an argument (typically aSymbolorString) to contract functions such asfund_escrow,get_legal_hold, orsettle. - Storage: The contract uses the
invoiceIdas part of the storage key (e.g.,InstanceorPersistentstorage) to track the state of a specific escrow. - Identifier Support: LiquiFact supports
invoiceIdstrings up to 128 characters (alphanumeric, underscores, and hyphens).
Note: For Soroban-only operations, there is no technical requirement to use the Stellar transaction memo field for correlation, as the contract call itself contains the identifier.
When using Stellar classic payments (e.g., simple Payment operations) alongside or instead of Soroban, the Stellar Memo field is used for correlation.
- Mechanism: The
invoiceIdis stored in the transaction'smemofield. - Mapping:
- MEMO_TEXT: Limited to 28 bytes. If the
invoiceIdis 28 characters or fewer (ASCII), it can be stored directly. - Internal Registry: The
escrow_operationstable in the backend database acts as the primary mapping registry. It links theinvoice_id(UUID) to thestellar_transaction_hash. - MEMO_HASH: For
invoiceIdvalues that cannot be stored inMEMO_TEXT, the backend can use a 32-byteMEMO_HASHderived from theinvoiceId. Theescrow_operationstable is used to resolve this hash back to the originalinvoiceId.
- MEMO_TEXT: Limited to 28 bytes. If the
- Recommendation: It is recommended to keep
invoiceIdshort (e.g., UUIDs or short slugs) if they need to fit directly into aMEMO_TEXTfield.
| Feature | Soroban Strategy | Stellar Classic Strategy |
|---|---|---|
| Identifier | Contract Argument | Transaction Memo |
| Scope | Contract-local | Ledger-wide (via transaction) |
| Constraint | 128 characters | 28 bytes (TEXT) or 32 bytes (HASH) |
| Ambiguity | Low (scoped to contract) | Medium (requires memo parsing) |
- Validation: All
invoiceIdvalues must be validated against the allowed pattern (/^[a-zA-Z0-9_-]{1,128}$/) before being passed to on-chain operations to prevent injection or malformed storage keys. - Privacy: While
invoiceIdvalues are generally not sensitive, be aware that they are visible on-chain when used in Soroban arguments or Stellar memos. Use opaque identifiers if privacy is a concern.
Stellar classic payment memos are limited to 28 bytes. The escrow
submission prefixes every memo with lq: (3 bytes), leaving 25 bytes
for the invoiceId.
submitFundEscrowcallsbuildMemo(invoiceId)before building the transaction.buildMemomeasures the full memo byte-length withBuffer.byteLength.- If the memo exceeds 28 bytes, it throws an
EscrowSubmitErrorwith a clear message — the transaction is never submitted with a truncated memo. - No silent truncation is permitted; callers must ensure
invoiceIdis short enough to fit, or use an alternative correlation strategy.
A truncated memo no longer maps back to the invoice during indexing, breaking on-chain-to-DB correlation. Failing loudly prevents silent data loss.