Skip to content

Repository files navigation

📦 TrustFlow SDK

License: MIT TypeScript

Type-safe TypeScript SDK for building gig-economy applications on the TrustFlow Protocol (Stellar/Soroban).

The TrustFlow SDK provides a developer-friendly interface for interacting with TrustFlow smart contracts on the Stellar network. Build escrow systems, dispute resolution platforms, and decentralized freelance marketplaces with clean, type-safe APIs.


⚡ Quick Start

Installation

npm install @trustflow/sdk
# or
yarn add @trustflow/sdk

1 — Connect to the Network

import { TrustFlowClient } from '@trustflow/sdk';

const client = new TrustFlowClient({
  contractId: process.env.TRUSTFLOW_CONTRACT_ID!,
  network: 'TESTNET', // or 'MAINNET'
});

await client.connect();
console.log('Connected to', client.network);

2 — Create an Escrow

import { TrustFlowEscrowClient, EscrowBuilder } from '@trustflow/sdk';

const escrowClient = new TrustFlowEscrowClient({
  contractId: process.env.TRUSTFLOW_CONTRACT_ID!,
  network: 'TESTNET',
  rpcUrl: 'https://soroban-testnet.stellar.org',
  networkPassphrase: 'Test SDF Network ; September 2015',
});

const params = new EscrowBuilder()
  .setDepositor('GDEPOSITOR...')
  .setBeneficiary('GBENEFICIARY...')
  .setAmount('50') // XLM
  .setDeadline(17280) // ~1 day in ledgers
  .build();

const result = await escrowClient.createEscrow(params);
if (result.ok) {
  console.log('Escrow ID:', result.data.escrowId);
  console.log('Tx Hash:', result.data.txHash);
}

3 — Fund & Release an Escrow

import { TrustFlowClient } from '@trustflow/sdk';
import { createEscrow, releaseEscrow } from '@trustflow/sdk/escrow';
import { connectWallet } from '@trustflow/sdk/wallet';
import { xlmToStroops } from '@trustflow/sdk/utils';

const wallet = await connectWallet('freighter');
const client = new TrustFlowClient({
  contractId: process.env.TRUSTFLOW_CONTRACT_ID!,
  network: 'TESTNET',
});
await client.connect();

// Create
const escrow = await createEscrow(client, {
  sender: wallet.publicKey,
  recipient: 'GRECIPIENT...',
  amountStroops: xlmToStroops('50'),
  durationBlocks: 17280,
  metadata: { orderId: 'ORD-001' },
});
console.log('Escrow created:', escrow.id);

// Release
const txHash = await releaseEscrow(client, {
  escrowId: escrow.id,
  caller: wallet.publicKey,
});
console.log('Released! Transaction:', txHash);

See docs/QUICKSTART.md for the full walkthrough including disputes, multi-sig, and pagination.

Multi-Sig Escrow (M-of-N)

Collect signatures from multiple approvers before a release is broadcast:

import { MultiSigEscrowClient } from '@trustflow/sdk';
import { Networks } from '@stellar/stellar-sdk';

const client = new MultiSigEscrowClient({
  contractId: process.env.TRUSTFLOW_CONTRACT_ID!,
  network: 'TESTNET',
  rpcUrl: 'https://soroban-testnet.stellar.org',
  networkPassphrase: Networks.TESTNET,
});

// Register a 2-of-2 release operation
const { data: { operationId } } = client.initMultiSigOperation({
  escrowId: 'esc-42',
  signers: [APPROVER_A, APPROVER_B],
  threshold: 2,
  operationType: 'release',
  unsignedXdr: UNSIGNED_RELEASE_XDR,
  networkPassphrase: Networks.TESTNET,
});

// Each approver submits their signed XDR independently
client.addSignature({ operationId, signerAddress: APPROVER_A, signedXdr: SIGNED_XDR_A });
client.addSignature({ operationId, signerAddress: APPROVER_B, signedXdr: SIGNED_XDR_B });

// Broadcast once threshold is met
const result = await client.submitWhenReady(operationId, 'https://horizon-testnet.stellar.org');
console.log('Released! tx:', result.data?.txHash);

See examples/multisig-escrow.ts for the full walkthrough.

Juror Voting

Cast a juror's vote on a dispute, either in the open or as ciphertext (e.g. for a commit-reveal scheme — the SDK does not perform the encryption itself, ciphertext must already be base64-encoded by the caller):

import { JurorClient } from '@trustflow/sdk';

const jurors = new JurorClient({
  contractId: process.env.TRUSTFLOW_CONTRACT_ID!,
  network: 'TESTNET',
  rpcUrl: 'https://soroban-testnet.stellar.org',
  networkPassphrase: 'Test SDF Network ; September 2015',
});

// Plaintext vote
const result = await jurors.vote({
  disputeId: 'dsp-1',
  jurorAddress: 'GJUROR...',
  vote: { encrypted: false, choice: 'approve' },
});

// Encrypted vote (commit-reveal style)
const encryptedResult = await jurors.vote({
  disputeId: 'dsp-1',
  jurorAddress: 'GJUROR...',
  vote: { encrypted: true, ciphertext: myCiphertext.toString('base64') },
});

if (result.ok) console.log('Voted! tx:', result.data.txHash);

Session Storage (Browser vs Node)

saveSession / loadSession / clearSession detect their environment per call (via typeof localStorage), so no setup is needed in either place:

  • Browser: uses localStorage automatically — sessions survive page reloads.

  • Node / CLI / backend: falls back to an in-memory store scoped to the current process. This does not survive process restarts. If you need durability (a long-running server, a CLI invoked repeatedly), inject your own adapter:

    import { configureSessionStorage } from '@trustflow/sdk';
    
    configureSessionStorage({
      get: (key) => myFileOrRedisStore.get(key),
      set: (key, value) => myFileOrRedisStore.set(key, value),
      remove: (key) => myFileOrRedisStore.delete(key),
    });
  • SSR / bundler edge cases (Next.js, Remix, etc.): typeof localStorage can be ambiguous when server and client code share a module graph. If session calls run on the server during SSR, they'll silently use the in-memory fallback for that request rather than throwing — which is usually not what you want. Call configureSessionStorage() explicitly with a no-op or server-appropriate adapter for server-rendered code paths, and only rely on the automatic localStorage detection in code you know runs client-side.

Sessions also carry an expiresAt, checked via isSessionExpired(). This is a best-effort, client-side value — the backend does not currently return a token TTL (tracked in #82), so treat it as a lower bound, not a guarantee, and still handle a 401 from the backend even when isSessionExpired() returns false.

Multisig Cross-Process Coordination

MultiSigEscrowClient keeps operation state in-memory per process. To coordinate signers running in separate processes today, round-trip state through your own store with exportState() / importState():

// Process A (initiator)
const snapshot = client.exportState(operationId); // -> hand this to your own backend/queue

// Process B (a signer), after fetching that snapshot from your store
const imported = client.importState(snapshot);
if (!imported.ok) {
  throw new Error(imported.error); // malformed/corrupted snapshot
}
client.addSignature({ operationId, signerAddress, signedXdr });
const reExported = client.exportState(operationId); // hand the updated state back to your store

importState overwrites any existing local operation with the same operationIdlast write wins. If two processes both mutate after diverging from the same snapshot and both re-export, importing one after the other discards the first's signatures rather than merging them. Serializing concurrent writes (e.g. one writer at a time through your store) is the caller's responsibility until a native, backend-backed MultiSigStateStore lands — tracked in #83.


✨ Features

Current Capabilities

  • 🔐 Escrow Management: Create, fund, release, and monitor escrows
  • 🚀 Transaction Pipeline: Assemble, simulate, auto-adjust resource fees, fee-bump, and retry Soroban transactions via TransactionPipeline, with typed PipelineResult<T> errors
  • ✍️ Multi-Sig Escrows: M-of-N signature collection for shared backend Escrows via MultiSigEscrowClient
  • ⚖️ Dispute Resolution: Raise and track disputes with on-chain governance
  • 🗳️ Juror Voting: Cast plaintext or encrypted votes on disputes via JurorClient
  • 🔁 Backend API Auto-Retries: Resilient backend calls via axios-retry for transient failures
  • 🔑 Wallet Integration: Built-in support for Freighter wallet
  • 📊 Event Monitoring: Real-time escrow state change tracking
  • 🛡️ Type Safety: Full TypeScript support with Zod validation schemas
  • 🧪 Test Coverage: Comprehensive Jest test suite

Architecture Highlights

  • Result Types: No thrown exceptions in public APIs — all errors returned as SDKResult<T>
  • Immutable Builders: Fluent APIs like EscrowBuilder for parameter construction
  • Network Agnostic: Easily switch between Testnet and Mainnet
  • Pure Utilities: Side-effect-free helper functions for formatting and validation

Read more in docs/ARCHITECTURE.md


📚 Documentation


🗺️ Roadmap

The SDK is under active development. Here's what's coming:

In Progress

  • Tsup bundler configuration for ESM/CJS exports
  • NPM publishing pipeline with provenance
  • Simulation wrappers for transaction cost estimation (TransactionPipeline)
  • Auto-retry logic for backend API endpoints (axios-retry)

Planned Features

  • Multi-signature support for corporate escrows
  • IPFS storage helpers for file uploads
  • Pagination support for high-volume queries
  • Event parsing utilities for XDR decoding
  • Juror voting system integration

See our GitHub Issues for detailed progress tracking.


🤝 Contributing

We welcome contributions! To get started:

  1. Fork the repository
  2. Install dependencies: npm install
  3. Run tests: npm test
  4. Submit a PR

Please ensure:

  • Tests pass (npm test)
  • Linting passes (npm run lint)
  • Code is formatted (npm run format)

Check CONTRIBUTING.md for detailed guidelines.


🔒 Security

  • Strict Linting: ESLint strict mode enforced across the codebase
  • Input Validation: All parameters validated with Zod schemas
  • Type Safety: TypeScript strict mode prevents runtime errors
  • Test Coverage: Critical paths covered by Jest integration tests

Report security issues to: security@trustflow.xyz


📜 License

MIT License - Copyright (c) 2026 TrustFlow Protocol

See LICENSE for details.


🌟 Community


Securing the future of work, one transaction at a time.

About

No description or website provided.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages