Skip to content

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

 
 

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);

Claiming Escrow Funds

Once an escrow has cleared for release, the beneficiary can withdraw funds directly with claim — a shortcut that doesn't require a separate release step from the depositor:

const result = await escrowClient.claim('esc-42', 'GBENEFICIARY...');
if (result.ok) console.log('Claimed! tx:', result.data.txHash);

IPFS Storage

Every TrustFlowClient exposes a built-in storage.upload() helper for pinning files to IPFS (evidence attachments, gig deliverables, dispute exhibits, etc.):

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

const client = new TrustFlowClient({
  contractId: process.env.TRUSTFLOW_CONTRACT_ID!,
  ipfs: { apiKey: process.env.IPFS_API_KEY },
});

const result = await client.storage.upload(fileBuffer, { filename: 'contract.pdf' });
if (result.ok) console.log('Uploaded:', result.data.url);

IPFSStorage can also be used standalone via new IPFSStorage(config), and points at a web3.storage-compatible raw-body upload API by default — pass apiUrl to target a different IPFS pinning service.

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 operationId — last 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
  • 📦 IPFS Storage: Upload files to IPFS via client.storage.upload() or standalone IPFSStorage
  • 🔁 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


⚛️ React Hooks

React hooks for wallet, balance, and transaction state are available from the @trustflow/sdk/react subpath, kept separate from the main entrypoint so non-React (Node/CLI) consumers aren't forced to install react:

import { useWallet, useBalance, useTransaction } from '@trustflow/sdk/react';

react (^18.0.0 || ^19.0.0) is a peer dependency, required only if you import from /react. Note: useEscrow is not yet exported here — it's implemented against an API that doesn't currently exist on TrustFlowClient (tracked in #81).


📚 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, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages