Data Model

Domain entities, field definitions, and key design decisions.

Entities

Transaction

The central entity in the Sankofa Engine. Represents any ledger operation – debits, credits, transfers, exchanges, minting, and burning.

FieldTypeDescription
account_idstringAccount identifier. ASCII-only, max 128 characters, allowed: a-zA-Z0-9_.-:
amountstringTransaction amount (string, not float – see Amounts as Strings). Max 18 integer + 18 decimal digits.
typeenumTransaction type: debit, credit, transfer, exchange, mint, burn
statusenumProcessing status: pending, completed, failed
signaturestringECDSA P-256 signature from the submitting client
shard_iduint32Assigned shard (computed via FNV-1a hash of account_id)
idempotency_keystringClient-provided deduplication key
group_idstring (optional)UUID linking related transactions (e.g., both sides of a transfer)
token_idstring (optional)Associated fungible token identifier
token_classstring (optional)Associated NFT class identifier
audit_hashstringSHA-256 hash chain entry for tamper detection
receipt_signaturebytesECDSA P-256 DER-encoded receipt signature from the engine
created_atdatetimeCreation timestamp

FungibleToken

Represents a fungible token definition (e.g., a currency or point system).

FieldTypeDescription
idstringUnique token identifier
symbolstringToken symbol (e.g., USD, POINTS)
decimalsintegerDecimal precision, 0–18
issuerstringAccount ID of the token issuer
total_supplystringTotal supply (string for precision – see Amounts as Strings)
statusenumToken status: active, frozen, deprecated
created_atdatetimeCreation timestamp

NFTClass

Defines a class (template) for non-fungible tokens.

FieldTypeDescription
idstringUnique class identifier
namestringHuman-readable class name
descriptionstringClass description
issuerstringAccount ID of the class creator
metadata_schemaJSON SchemaJSON Schema defining valid metadata for instances of this class
statusenumClass status: active
created_atdatetimeCreation timestamp

NFTInstance

An individual non-fungible token, minted from an NFTClass.

FieldTypeDescription
class_idstringParent NFTClass identifier
instance_idstringUnique instance identifier within the class
owner_accountstringCurrent owner’s account ID
metadataJSONInstance-specific metadata (validated against class metadata_schema)
statusenumInstance status: active, burned
minted_atdatetimeMinting timestamp

SignedReceipt

A cryptographically signed proof that the engine processed a transaction. Returned to clients as confirmation.

FieldTypeDescription
group_idstringGroup identifier linking related transactions
account_idstringAccount that submitted the transaction
amountstringTransaction amount
typeenumTransaction type
audit_hashstringHash chain entry at time of processing
shard_iduint32Shard that processed the transaction
timestampdatetimeProcessing timestamp
signaturebytesECDSA P-256 DER-encoded engine signature over receipt fields

Key Design Decisions

Amounts as Strings

IEEE 754 floating-point arithmetic cannot represent decimal fractions exactly. For example, 0.1 + 0.2 produces 0.30000000000000004 in most languages. Financial systems require exact decimal arithmetic to avoid rounding errors that compound over millions of transactions.

All amounts in the Sankofa Engine are represented as strings (e.g., "100.50", not 100.50). Arithmetic is performed using arbitrary-precision decimal libraries, never floating-point.

FNV-1a Shard Routing

Transactions are assigned to shards deterministically using the FNV-1a hash of the account ID:

shard_id = FNV-1a(account_id) % shard_count

This approach ensures that all transactions for a given account are routed to the same shard, enabling per-account ordering guarantees without a centralized lookup service.

Idempotency

Every transaction submission must include a client-provided idempotency_key. If a duplicate key is received, the engine returns the original receipt without reprocessing. This key is also used as the NATS Nats-Msg-Id header, leveraging NATS JetStream’s built-in server-side deduplication window.

Audit Hash Chain

Each transaction’s audit_hash is computed as a chained SHA-256 hash over the previous hash and the current transaction fields:

SHA-256(prevHash || idempotencyKey || accountID || amount || type || createdAt_RFC3339Nano)

This creates a per-account append-only hash chain. Any tampering with historical records breaks the chain, making unauthorized modifications detectable.