@hsuite/smart-engines-sdk
v3.2.0
Published
Simplified client SDK for Smart Engines multi-chain infrastructure
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 — Web3 auth + register a smart-app
The canonical smart-app bootstrap flow:
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. Construct the BaaS client
const baas = new BaasClient({
hostUrl: 'https://v3-testnet-gateway.hsuite.network',
appId: 'pending', // will be replaced after register()
pathPrefix: '/host', // gateway routes /host/* → smart-host
});
// 3. Authenticate via Web3 challenge-response
// Cluster verifies with ripple-keypairs.verify(messageHex.toUpperCase(), signature, publicKey)
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 free_testnet 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 });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.
Available clients
| Client | Purpose |
|---|---|
| BaasClient | Authentication + database + storage + functions + messaging + deployment + agents |
| SmartEngineClient | Chain operations: account create, token create / mint / burn / freeze / wipe, transfers, HCS topics, TSS, IPFS |
| SmartGatewayClient | Gateway operations: routing, domains, DNS |
| ValidatorAuthClient | Standalone Web3 challenge-response auth (lower-level than BaasClient.authenticate) |
| ValidatorDiscoveryClient | HCS-registry-based validator discovery |
| TSSClient, IPFSClient, TransactionsClient, SettlementClient, SnapshotsClient | Direct sub-client access for advanced flows |
| MirrorNodeClient | Hedera mirror-node helper (when your app does Hedera-side queries) |
All clients accept the same pathPrefix: '/host' option when consumed via
the cluster gateway. Set pathPrefix: '' for direct host access.
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:
import { SmartEngineClient } from '@hsuite/smart-engines-sdk';
const client = new SmartEngineClient({
baseUrl: 'https://v3-testnet-gateway.hsuite.network',
// Auth via authToken (set after the Web3 challenge flow):
authToken: '<jwt-from-validator-auth-verify>',
});
// 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) => ({
baseUrl: 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 is a single 134 KB CJS bundle with workspace-only primitives
vendored in. Single-file .d.ts (84 KB) for full type ergonomics.
@hsuite/[email protected]
dist/index.js 134 KB — main bundle
dist/index.d.ts 84 KB — types
dist/nestjs/index.js 104 KB — NestJS integration
dist/nestjs/index.d.ts 64 KBLicense
MIT. Built on the Smart Engines V3 architecture (github.com/HSuiteNetwork/smart-engines-multichain).
