Skip to content

Hedera Hashgraph Integration

Live

Hedera is one of the two live chains in Smart Engines; XRPL is the other. It runs on the Smart Engines testnet, whose validators HSuite operates, against Hedera testnet.

The platform itself uses Hedera for one service: the Hedera Consensus Service (HCS), an ordered, timestamped public log. The canonical rules, the validator registry, governance and audit records are written to HCS topics.

The HSUITE token and the membership and subscription NFTs are not on Hedera. They are issued on XRPL.

A smart app can also create its own Hedera entities: accounts, HCS topics and fungible HTS tokens. Each one is controlled by a native Hedera KeyList whose keys come from a distributed key generation (DKG) across the validators.

flowchart TD
    HED["Hedera"] --> HCS["HCS topics"]
    HCS --> RULES["Canonical rules"]
    HCS --> REG["Validator registry"]
    HCS --> GOV["DAO governance"]
    HCS --> AUD["Audit logs"]
    HED --> APP["Smart-app entities"]
    APP --> ACC["Accounts"]
    APP --> TOP["Topics"]
    APP --> TOK["Fungible HTS tokens"]
    APP --> KL["Native KeyList<br/>(t-of-n DKG keys)"]

Hedera Consensus Service (HCS)

The public log for rules, the validator registry, governance and audit records

Topic entities

Your app’s own HCS topics; every submit is co-signed by the validators after the rules allow it

Account and token entities

Hedera accounts and fungible HTS tokens controlled by a validator KeyList

Native multisig

A Hedera KeyList with a threshold; each key is a DKG key held only as shares

Mirror node reads

State is read from Hedera’s public mirror node


A smart app can create a fungible HTS token as a token entity, bound to a published rule.

A Hedera token entity is created with two keys: the admin key and the supply key. Both are the entity’s DKG KeyList, so the validators threshold-sign every supply change, and only after the token’s rule allows it.

The token has no pause, freeze, KYC or wipe key, so those controls do not apply to it. Use XRPL when a token needs issuer compliance controls.

A Hedera token has no payer-funded create: pass platformPaid: true. The validator quorum signs the TokenCreate and the platform pays the Hedera fee. This is allowed for the app’s own create, or for a customer the app sponsors on that call.

// `baas` is a connected BaasClient from @hsuite/smart-engines-sdk (see the SDK guide).
const token = await baas.entities.createToken({
chain: 'hedera',
name: 'My Token',
symbol: 'MTK',
decimals: 6,
initialSupply: '1000000',
ruleRef, // the published rule that governs this token
platformPaid: true,
});

Passing fundWith for a Hedera token is refused before any call. See the SDK guide for ruleRef, async admission ({ wait: false }) and baas.operations.


Smart Engines does not create Hedera NFTs. A Hedera token entity is always fungible. The platform’s membership and subscription NFTs are XLS-20 NFTs on XRPL.


HCS provides a public log of messages with a guaranteed order and consensus timestamps. Smart Engines uses it for:

Validator Rule Storage

Every canonical rule is published to the rules topic

Entity Registry

The validator registry and entity bindings

Consensus Coordination

Consensus operations and DAO governance topics

Audit Logging

Settlement, PQC attestation and credential-rotation audit topics

A topic entity is created payer-funded. The validators attach the admin-key threshold signature, and the payer signs and submits the TopicCreate with their own wallet.

const topic = await baas.entities.createTopic({
chain: 'hedera',
ruleRef, // the rule must enable operations.submit for messages to be accepted
fundWith, // signs + submits the prepared TopicCreate with the payer's wallet
});

To drive the steps yourself, call baas.entities.prepareCreateTopic and then baas.entities.executeCreateTopic, passing the create transaction id so the cluster can read the new 0.0.X topic id from the receipt. platformPaid: true is also accepted in place of fundWith.

A topic entity’s submit_key is its own DKG KeyList. Your app cannot post to it with its own @hashgraph/sdk operator key: Hedera rejects that with INVALID_SIGNATURE. Submit through the SDK instead, which goes through the validators’ rule check.

Submitting to a Topic Entity (DKG-signed, payer-funded)

Section titled “Submitting to a Topic Entity (DKG-signed, payer-funded)”
// POST /api/v3/baas/entities/:entityId/message
const { transactionId } = await baas.entities.submitMessage(topic.entityId, {
message: JSON.stringify({ type: 'NOTE', body: 'hello' }),
payerAccountId: '0.0.1234', // omit to use the smart-app session wallet
fundWith, // the payer's own wallet signs + submits
});
// Or prepare the bytes and sign + submit them yourself:
const prepared = await baas.entities.prepareSubmitMessage(topic.entityId, {
message: JSON.stringify({ type: 'NOTE', body: 'hello' }),
});

The host takes the topic id from the entity record, never from your request.

Rule / limit Behavior
operations.submit The topic’s rule must enable it, or the submit is denied (403)
One HCS chunk Message must be 1..1024 UTF-8 bytes; empty or oversized is refused (400)
Chain Hedera only; a non-topic entity or a non-Hedera chain is refused (400)
Payer The payer signs and submits with their own wallet; the platform does not pay

The SDK counts UTF-8 bytes, not characters, and refuses an empty or oversized message before any call.

The single-chunk cap comes from threshold signing. A message over 1024 bytes would make Hedera split the submit into several transactions, but the validators sign exactly one transaction body. The later chunks would carry no valid submit-key signature.

Every Hedera entity is bound to its rule on chain. The memo of the entity’s creation transaction carries a rule reference of the form rule:<topicId>@<consensusTimestamp>:<entityType>, pointing at the rule’s message on the rules topic. A transaction memo cannot be changed after consensus. Before releasing a signature, the validators resolve the rule from HCS and check it against the entity’s record. A mismatch is denied.


A Hedera account entity is created payer-funded: prepare, your fundWith signs and submits the AccountCreate, then execute. The account’s key is the entity’s DKG KeyList, set in the create transaction itself, so the account is multisig from its first consensus timestamp.

const account = await baas.entities.createAccount({
chain: 'hedera',
ruleRef,
fundWith,
// Required when the rule's security mode is 'partial': the app owner's key
// is nested into the account KeyList ("owner AND validators").
appOwnerPublicKey,
});

Without appOwnerPublicKey, a Hedera account whose rule resolves to partial security is refused (400).


Value moves from an account entity through the entity-scoped methods. The entity is the source and the fee payer, and both are resolved server-side. You get prepared bytes to sign and submit. The host never submits and never pays.

const prepared = await baas.entities.transfer(account.entityId, {
chain: 'hedera',
to: '0.0.5678',
amount: '100000000', // tinybar (1 HBAR)
});
// prepared.transactionBytes: sign + submit with your wallet

A malformed account or token id is refused with 400 before anything is built.


The validators read Hedera state (accounts, token balances, topic messages, transaction records) from Hedera’s public mirror node. You can read the same data yourself.

Endpoint Method Description
/api/v1/transactions/{id} GET Get a transaction by id
/api/v1/tokens/{id} GET Get token information
/api/v1/tokens/{id}/balances GET Get a token’s holder balances
/api/v1/accounts/{id}/tokens GET Get an account’s token balances
/api/v1/topics/{id}/messages GET Get a topic’s messages
/api/v1/network/nodes GET Get network node information

The testnet mirror node is https://testnet.mirrornode.hedera.com, and the explorer is https://hashscan.io/testnet.


Smart Engines does not deploy or call Hedera smart contracts. Its Hedera footprint is HCS topics, accounts and HTS tokens.


Limit Value
HCS message (topic entity) 1024 UTF-8 bytes (one chunk)
Max transaction size 6 KB (Hedera network limit)
Max memo length 100 bytes (Hedera network limit)

Every key that controls a Hedera entity is a native Hedera KeyList with a threshold t of n keys, one key per validator slot.

  • Each key is born split. Each slot key is created by a distributed ed25519 DKG (Feldman VSS) across the validators. Only shares are stored, and the key is never written whole.
  • Never assembled, even to sign. Signing is two-round FROST threshold signing: t validators each produce a partial signature with their own share, and only the partial signatures are combined. The slot key never exists whole, and no share leaves its validator.
  • Rules first. Each validator signs its part only after the entity’s rule allows the operation.
  • Threshold. The threshold must be a strict majority that is also above the tolerated faulty coalition ⌊(n−1)/3⌋. See DKG and TSS.

The cluster’s internal BLS keys never appear on Hedera.


These are Hedera network status codes you may meet when you submit a prepared transaction.

Error Cause Solution
INSUFFICIENT_PAYER_BALANCE The payer lacks HBAR Fund the payer account
INVALID_SIGNATURE A required key is missing Submit through the SDK, not your own operator key
TOKEN_NOT_ASSOCIATED_TO_ACCOUNT Token not associated Associate the token with the account
TOKEN_HAS_NO_PAUSE_KEY Token has no pause key Hedera token entities have no pause key

Publish the rule first

Every entity is created against a published rule; a topic needs operations.submit enabled

Keep your payer key yourself

The SDK never holds your chain key; fundWith signs with your own wallet

Partial security needs your key

Pass appOwnerPublicKey for a Hedera account whose rule is partial

Least privilege

Enable only the operations the rule needs

Read from the mirror node

Use the mirror node for history and balances

Follow slow creates

Use { wait: false } and baas.operations instead of holding a request open

Payer-funded by default

On the payer-funded paths your payer wallet pays the Hedera fee

Size messages

Keep each topic message within one 1024-byte chunk