@hsuite/smart-engines-sdk
v5.3.0
Published
Simplified client SDK for Smart Engines multi-chain infrastructure
Maintainers
Readme
@hsuite/smart-engines-sdk
Client SDK for the Smart Engines V3 multi-chain platform. Build smart-apps and smart-agents that authenticate via Web3 challenge-response, talk to the network's BaaS surface (database, storage, messaging, functions, deployment), and execute chain operations across Hedera, XRPL, Polkadot, Solana, Stellar, EVM, and Bitcoin.
npm install @hsuite/smart-engines-sdkPlus the peer deps your app actually uses:
npm install xrpl # required — XRPL is canonical for auth
npm install @hashgraph/sdk # only if your app does Hedera-side ops
npm install @nestjs/common @nestjs/core # only if you use the NestJS integration
npm install zod # peer (likely transitive in your app already)Quick start — connectToCluster
connectToCluster is the canonical entrypoint: it auto-discovers an active
cluster via the service registry, picks one at random, runs Web3 auth, and
hands back a wired client. Zero hand-rolled URLs, zero validator pinning,
permissionless cluster join/leave is invisible to the SDK caller.
BaaS (smart-app primary path)
import { BaasClient } from '@hsuite/smart-engines-sdk';
import { Wallet } from 'xrpl';
import { sign as xrplSign } from 'ripple-keypairs';
// 1. Your XRPL wallet (real production: load XRPL_SEED from env / secret store)
const wallet = Wallet.fromSeed(process.env.XRPL_SEED!);
// 2. Connect to the network (zero-config — testnet | mainnet)
const baas = await BaasClient.connectToCluster({
network: 'testnet',
});
// 3. Web3 auth (challenge-response over the discovered cluster's gateway)
await baas.authenticate({
chain: 'xrpl',
walletAddress: wallet.address,
publicKey: wallet.publicKey,
signFn: (message) => {
const messageHex = Buffer.from(message, 'utf-8').toString('hex').toUpperCase();
return xrplSign(messageHex, wallet.privateKey);
},
});
// 4. Initialise a smart-app via the four-step deploy flow
// (init → docker push → optional uploadFrontend → deploy). `init` runs
// the per-entity DKG ceremony on the cluster and returns the DKG entityId
// as `appId`, plus ephemeral push credentials for the cluster's per-tenant
// Harbor project (single-use secret — not persisted server-side).
const init = await baas.deployment.init({
name: 'my-smart-app',
port: 3000,
services: ['database', 'storage', 'messaging', 'functions'],
});
console.log(`Allocated smart-app ${init.appId}`);
console.log(`Push to: ${init.registry.server}/${init.registry.repository}:<tag>`);
baas.setAppId(init.appId);
// (out-of-band) docker login + docker push <init.registry.server>/<init.registry.repository>:v1
// (optional) await baas.deployment.uploadFrontend(init.appId, await fs.readFile('./bundle.tar.gz'));
// (deploy) await baas.deployment.deploy(init.appId, { tag: 'v1', replicas: 1 });SmartEngineClient (direct chain operations)
import { SmartEngineClient } from '@hsuite/smart-engines-sdk';
const { client, validator, session } = await SmartEngineClient.connectToNetwork({
network: 'testnet', // resolves a real validator origin from the HCS registry
chain: 'xrpl',
address: wallet.address,
publicKey: wallet.publicKey,
signFn: (challenge) => /* sign the challenge */ '',
});
// All sub-clients are wired against the discovered validator
await client.tss.signMPC({ chain: 'hedera', entityId: '...', transactionBytes: '0x...' });
await client.ipfs.upload(file, 'document.pdf');Why XRPL? Per the Smart Engines V3 architecture, XRPL is canonical for smart-app authentication and registration. The cluster's validator/host pods pay their own HCS fees from pod-local operator accounts; smart-apps never need Hedera credentials for the framework. Smart-apps can still target any chain (Hedera, Solana, …) for their own business logic — that's separate from the dev wallet used to authenticate.
Faster bootstrap? Use the @hsuite/smart-engines-cli — hsuite init generates a fresh XRPL wallet + funds it via the testnet faucet + writes .env.local, then hsuite subscribe registers the smart-app in one command.
Manual override — pin a host directly
If you need to point the SDK at a specific gateway / host (private deployment, local k3d cluster, conformance harness), bypass discovery and pass a URL:
import { BaasClient, SmartEngineClient } from '@hsuite/smart-engines-sdk';
const baas = new BaasClient({
hostUrl: 'https://v3-testnet-gateway.hsuite.network',
appId: 'pending',
pathPrefix: '/host', // gateway routes /host/* → smart-host
});
// `SmartEngineClient` is validator-direct: `validatorBaseUrl` MUST be a
// validator origin, NEVER the gateway. Its raw `/api/v3/*` tier is un-ingressed
// at the gateway (RFC #1236), so a gateway URL here 404s every call.
const client = new SmartEngineClient({
validatorBaseUrl: 'http://smart-validator:3000', // in-cluster validator origin
authToken: '<jwt-from-validator-auth-verify>',
});You can also pass bootstrap: string[] to connectToCluster for explicit
seed lists (private deployments).
Available clients
The root SmartEngineClient exposes every sub-client below — each maps 1:1
to a server-side controller. BaasClient mirrors the host/BaaS surface.
Top-level clients
| Client | Purpose |
|---|---|
| BaasClient | Authentication + database + storage + functions + messaging + deployment + agents + rules + entities |
| SmartEngineClient | Chain operations + every typed sub-client below |
| SmartGatewayClient | Gateway operations: routing, domains, DNS |
| ValidatorAuthClient | Standalone Web3 challenge-response auth (lower-level than BaasClient.authenticate) |
| ClusterDiscoveryClient | Bootstrap-seed → active-cluster discovery (powers connectToCluster) |
| ValidatorDiscoveryClient | HCS-registry-based validator discovery (legacy connectToNetwork path) |
| MirrorNodeClient | Hedera mirror-node helper (when your app does Hedera-side queries) |
client.* sub-clients on SmartEngineClient
| Field | Purpose |
|---|---|
| client.subscription | Application subscription management |
| client.tss | Threshold Signature Scheme — chain-agnostic MPC operations |
| client.ipfs | IPFS decentralized file storage |
| client.transactions | Chain-agnostic prepare-sign-submit (transaction sovereignty) |
| client.hedera | Hedera-specific transaction preparation (HCS topics, KYC, wipe) |
| client.hedera.tss | Hedera TSS immediate-execute (cluster signs + submits in one call) |
| client.xrpl | XRPL-specific transaction preparation (trust lines) |
| client.solana | Solana-specific transaction preparation (close-account) |
| client.polkadot | Polkadot-specific transaction preparation (asset setTeam/setMetadata) |
| client.snapshots | Token holder snapshot generation and retrieval |
| client.historicalBalance | Historical balance archive reads |
| client.settlement | Cross-chain settlement operations |
| client.governance | Governance proposal dry-run (simulate-only) |
| client.dao | DAO governance — DAOs, proposals, votes, treasury, members, dashboard |
| client.personhood | Personhood verification (HPP one-human-one-member) |
| client.agents | BaaS smart-agent lifecycle (register/fund/trade/withdraw/pause/resume/revoke) |
| client.deployments | BaaS smart-app deployment lifecycle (init/uploadFrontend/deploy/rollback/status) |
| client.bridge | Universal Token Bridge — port/return/claim across chains |
| client.resources | Network + per-app resource consumption (summary, history, ledger, nodes) |
| client.envelope | AES-256-GCM envelope encrypt/decrypt under the TSS-backed master KEK |
| client.tokens | Token migration — move existing tokens to TSS-controlled keys |
| client.operator | Operator account funding helpers (balance + top-up guidance) |
| client.discovery | Discovery — cluster registry + client.discovery.platformImages manifests |
baas.* sub-clients on BaasClient
| Field | Purpose |
|---|---|
| baas.db | Trustless database with state proofs and Merkle verification |
| baas.storage | Decentralized file storage |
| baas.functions | Serverless function deployment and invocation |
| baas.messaging | Real-time pub/sub messaging with channels, history, presence |
| baas.deployment | App deployment lifecycle (init/uploadFrontend/deploy/rollback/...) |
| baas.agents | Autonomous smart-agent management |
| baas.customerSession | Customer→smart-app session bridge (TokenGate Face B) |
| baas.rules | Publish / get / list / simulate / deprecate canonical ValidatorRules documents on HCS |
| baas.entities | Create canonical token / account / topic / agent entities (plus launchpad mega-helper), each bound to a published ruleRef |
All clients accept the same pathPrefix: '/host' option when consumed via
the cluster gateway. Set pathPrefix: '' for direct host access.
Rules — author + publish canonical ValidatorRules
ValidatorRules are the canonical, HCS-pinned policy documents the cluster
quorum evaluates before signing any entity action (mint, burn, transfer,
trade, …). Smart-apps author rules locally (via templates or a fluent
builder), publish them to HCS via baas.rules.publish, and bind the
returned ruleRef into the entity at creation time via baas.entities.*.
Every action against the entity is then rules-checked + TSS-signed.
import { BaasClient, Rules } from '@hsuite/smart-engines-sdk';
// Template — opinionated fair-launch token with all knobs pre-set.
const rule = Rules.template.fairLaunch({
maxSupply: '1000000000',
mintWindow: { startsAt: '2026-06-01T00:00:00Z', endsAt: '2026-06-08T00:00:00Z' },
});
const { ruleRef } = await baas.rules.publish(rule);
const token = await baas.entities.createToken({
chain: 'hedera',
name: 'Fair Launch Token',
symbol: 'FAIR',
decimals: 6,
ruleRef,
});// Fluent builder — when you want to compose the rule yourself.
const rule = Rules.forToken()
.withSecurity('full') // 'none' | 'partial' | 'full'
.withOperations({
mint: { enabled: true, limits: { dailyLimit: '1000000' } },
burn: { enabled: true },
})
.withInvariants({ maxSupply: '1000000000' })
.build();
const { ruleRef } = await baas.rules.publish(rule);
const sim = await baas.rules.simulate({ ruleRef, action: 'mint', context: { amount: '500' } });
// sim.isValid === true | false (+ reason)Full reference: Smart-App SDK Guide
BaaS sub-clients
Once authenticated, every BaaS sub-client is reachable from a single
BaasClient instance:
Database (Merkle-anchored key-value store)
const record = await baas.db.insert('users', { name: 'Alice', role: 'developer' });
// → { document, stateTransition: { merkleProof, stateRoot, ... } }
const found = await baas.db.find('users', { role: 'developer' });
// → { documents: [...], count }
const updated = await baas.db.update('users', record.document._id, { role: 'admin' });
await baas.db.delete('users', record.document._id);Every write returns a cryptographic state-transition proof anchored on-chain — verifiable without re-reading the DB.
Storage (IPFS-backed)
const upload = await baas.storage.upload(file, 'avatar.png');
// → { fileId, cid, url: 'ipfs://bafy…', size }
const files = await baas.storage.list();
const usage = await baas.storage.getUsage();Messaging (pub/sub channels)
await baas.messaging.publish('events', { type: 'user.created', userId: '...' });
const sub = await baas.messaging.subscribe('events');Functions (verifiable compute)
const fn = await baas.functions.deploy({
name: 'compute-hash',
runtime: 'node20',
trigger: 'http',
code: '...', // your function source
});
const result = await baas.functions.invoke(fn.functionId, { input: '...' });
// Cluster runs in isolated sandboxes across the validator quorum;
// 2-of-3 TSS consensus required before result is signed.Smart Agents (autonomous workers)
const agent = await baas.agents.register({
name: 'Trading Bot',
capabilities: ['trade', 'withdraw'],
rules: {
maxTradeAmount: '1000',
allowedPairs: ['HBAR/USDC'],
dailyLimit: '5000',
requireApprovalAbove: '10000',
},
});
// Rules are pinned to HCS and enforced by the validator quorum.
// Every agent action is rules-checked, TSS-signed, then submitted on chain.
await baas.agents.fund(agent.agentId, { chain: 'hedera', amount: '500' });
await baas.agents.trade(agent.agentId, { chain: 'hedera', pair: 'HBAR/USDC', side: 'buy', amount: '100' });
await baas.agents.pause(agent.agentId);
await baas.agents.resume(agent.agentId);
const events = await baas.agents.getEvents(agent.agentId);Deployment (runtime orchestration — spec §6.1)
The four-step deploy flow: init → docker push → (optional) uploadFrontend → deploy.
// 1. init — allocate appId via DKG + receive ephemeral Harbor push credentials
const init = await baas.deployment.init({
name: 'my-smart-app',
port: 3000,
services: ['database', 'storage', 'messaging'],
});
// 2. docker push — out-of-band, using the ephemeral creds returned above
// docker login -u <init.registry.username> -p <init.registry.password> <init.registry.server>
// docker push <init.registry.server>/<init.registry.repository>:v1
// 3. uploadFrontend — optional SPA tarball (content-addressed, mounted read-only)
await baas.deployment.uploadFrontend(init.appId, await fs.readFile('./bundle.tar.gz'));
// 4. deploy — reconcile to k8s
const deployed = await baas.deployment.deploy(init.appId, {
tag: 'v1',
replicas: 1,
env: { NODE_ENV: 'production' },
});
console.log(`live at ${deployed.url}`);
// Lifecycle + listing
const apps = await baas.deployment.list();
const info = await baas.deployment.get(init.appId);
const status = await baas.deployment.status(init.appId);
await baas.deployment.suspend(init.appId);
await baas.deployment.resume(init.appId);
await baas.deployment.rollback(init.appId, { toTag: 'v0' });Chain operations via SmartEngineClient
For direct chain operations independent of BaaS — e.g., a custodial backend
that creates accounts and tokens on behalf of users — use the methods on the
SmartEngineClient returned by connectToNetwork:
import { SmartEngineClient } from '@hsuite/smart-engines-sdk';
const { client } = await SmartEngineClient.connectToNetwork({
network: 'testnet',
chain: 'xrpl',
address: wallet.address,
publicKey: wallet.publicKey,
signFn: async (challenge) => /* sign challenge */ '',
});
// Create an account on any supported chain
const account = await client.createAccount({
chain: 'hedera',
initialBalance: '10',
validatorTimestamp: '...',
validatorTopicId: '0.0.98765',
});
// Create a fungible token
const token = await client.createToken({
chain: 'hedera',
name: 'My Token', symbol: 'MTK',
decimals: 8, initialSupply: '1000000',
type: 'fungible',
capabilities: { mintable: true, burnable: true, pausable: true, restrictable: true, compliant: true, wipeable: true },
validatorTimestamp: '...', validatorTopicId: '0.0.98765',
});
// Transfer
const tx = await client.transfer({
chain: 'hedera', from: '0.0.1', to: '0.0.2', amount: '1.5',
validatorTimestamp: '...', validatorTopicId: '0.0.98765',
});
// Balance + info
const balance = await client.getBalance('hedera', '0.0.12345');
const info = await client.getAccountInfo('hedera', '0.0.12345');
// HCS topic ops, IPFS pinning, TSS signing — all available via sub-clients
await client.tss.signMPC({ chain: 'hedera', entityId: '...', transactionBytes: '0x...' });
await client.ipfs.upload(file, 'document.pdf');
await client.transactions.prepareTransfer({ chain: 'xrpl', from: '...', to: '...', amount: '100' });NestJS integration
// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { SmartEngineModule } from '@hsuite/smart-engines-sdk/nestjs';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
SmartEngineModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
validatorBaseUrl: config.get('VALIDATOR_URL')!,
timeout: 30000,
testConnection: true,
autoReconnect: true,
reconnectInterval: 5000,
}),
inject: [ConfigService],
isGlobal: true,
}),
],
})
export class AppModule {}Inject the SmartEngineService into your controllers / services for typed
access to client.getHealth() / client.createAccount() / ....
Resilience primitives
The SDK ships circuit-breaker, rate-limiter, and retry primitives used internally — exposed for app-level use too:
import { CircuitBreaker, RateLimiter, retryWithBackoff } from '@hsuite/smart-engines-sdk';
const breaker = new CircuitBreaker({ failureThreshold: 5, resetTimeoutMs: 30_000 });
const result = await breaker.execute(() => someFlakyOperation());
const limiter = new RateLimiter({ maxRequests: 60, windowMs: 60_000 });
if (limiter.isAllowed(walletAddress)) { /* proceed */ }
const value = await retryWithBackoff(
() => someTransientCall(),
{ maxRetries: 3, initialDelayMs: 200, backoffMultiplier: 2 },
);Error handling
import { SmartEngineError, ErrorCode, UnsupportedCapabilityError, BaasError } from '@hsuite/smart-engines-sdk';
try {
await client.createToken({ chain: 'xrpl', name: 'X', symbol: 'X', type: 'fungible', /* ... */ capabilities: { wipeable: true } });
} catch (err) {
if (err instanceof UnsupportedCapabilityError) {
console.error(`${err.capability} not supported on ${err.chain}; alternatives:`, err.alternatives);
} else if (err instanceof SmartEngineError && err.code === ErrorCode.RATE_LIMIT_EXCEEDED) {
// back off + retry
} else if (err instanceof BaasError) {
console.error('BaaS request failed:', err.statusCode, err.details);
}
}Peer dependencies
| Package | Required? | When |
|---|---|---|
| xrpl | required | Web3 auth signing (Wallet.fromSeed, wallet.publicKey, etc.) |
| zod | required | Schema validation (request/response shapes) |
| @nestjs/common + @nestjs/core | optional | Only if you import from @hsuite/smart-engines-sdk/nestjs |
| @hashgraph/sdk | optional | Only if your app does Hedera-side business logic |
ripple-keypairs is a transitive dep of xrpl — no separate install needed.
Bundle
The SDK ships as a single CJS bundle with workspace-only primitives
vendored in, plus subpath exports for the optional NestJS integration and
the customer-facing PQC verifiers. Build artifacts live under dist/:
dist/index.{js,d.ts} — main bundle + types
dist/nestjs/index.{js,d.ts} — NestJS integration (optional)
dist/pqc-verify/index.{js,d.ts} — PQC attestation verifier
dist/pqc-verify-envelope/index.{js,d.ts} — PQC envelope verifier
dist/ipfs-access-key/index.{js,d.ts} — IPFS access-key helper
dist/k8s-secret-reader/index.{js,d.ts} — k8s secret reader (NestJS)The PQC and k8s-secret-reader entries are subpath exports — import from
@hsuite/smart-engines-sdk/pqc-verify etc. so callers that don't need
@noble/post-quantum (~120 KB compressed) don't pull it in.
License
MIT. Built on the Smart Engines V3 architecture (github.com/HSuiteNetwork/smart-engines-multichain).
