Skip to content

Latest commit

 

History

History
360 lines (255 loc) · 12 KB

File metadata and controls

360 lines (255 loc) · 12 KB

conduit-sdk API Reference

Full method signatures, parameters, return types, and error conditions.


ConduitClient

new ConduitClient(config: ConduitConfig)

ConduitConfig

Field Type Required Default
network 'mainnet' | 'testnet' | 'local'
keypair Keypair For writes
rpcUrl string Network default
factoryAddress string Deployed factory
governorAddress string Deployed governor

client.streams

create(params) → Promise<CreateStreamResult>

Param Type Notes
recipient string Stellar G-address
token string 'native', 'USDC', or contract address
depositAmount string Display units, e.g. '1000'
durationSeconds number? Exclusive with ratePerSecond
startTime number? Unix timestamp; defaults to now
clawbackEnabled boolean? Default false
ratePerSecond string? Stroops/s; exclusive with durationSeconds

Throws: ConduitError with contract: 'factory'FactoryErrorCode.InvalidDeposit, .InsufficientDeposit, .BackdatedStream, .InvalidTimeRange, .RateExceedsMax, .DurationTooShort


get(streamId) → Promise<StreamInfo>

Fetches the complete stream state from the chain.


withdrawable(streamId) → Promise<bigint>

Current withdrawable balance in stroops. Read-only, no transaction.


withdraw(streamId, amount?) → Promise<string>

Param Type Notes
streamId bigint | string
amount bigint? Defaults to full withdrawable balance

Returns: Transaction hash
Requires: keypair set (recipient)
Throws: ConduitError with contract: 'stream'StreamErrorCode.NothingToWithdraw, .NotAuthorized, .StreamCancelled, .InvalidAmount


cancel(streamId) → Promise<string>

Atomically settles both parties (recipient gets owed amount, sender gets refund).

Requires: keypair set (sender)
Throws: ConduitError with contract: 'stream'StreamErrorCode.NotAuthorized, .StreamCancelled


pause(streamId) → Promise<string>

Freezes the stream clock. Withdrawable balance stops growing.

Requires: keypair set (sender)
Throws: ConduitError with contract: 'stream'StreamErrorCode.AlreadyPaused, .StreamCancelled


resume(streamId) → Promise<string>

Resumes a paused stream. Paused duration is excluded from streaming time.

Requires: keypair set (sender)
Throws: ConduitError with contract: 'stream'StreamErrorCode.NotPaused, .StreamCancelled


topUp(streamId, amount) → Promise<string>

Adds tokens to the stream balance. Extends effective stream duration.

Requires: keypair set (sender)
Throws: ConduitError with contract: 'stream'StreamErrorCode.StreamCancelled, .InvalidAmount


clawback(streamId) → Promise<bigint>

Reclaims unstreamed tokens. Only works if clawbackEnabled was true at creation.

Returns: Amount reclaimed (stroops)
Requires: keypair set (sender)
Throws: ConduitError with contract: 'stream'StreamErrorCode.ClawbackDisabled, .NotAuthorized


list(params) → Promise<StreamInfo[]>

Param Type Notes
sender string? Filter by sender address
recipient string? Filter by recipient address
offset number? Default 0
limit number? Default 20, max 100

subscribe(streamId, handlers) → Subscription

Poll for on-chain events.

const sub = client.streams.subscribe(streamId, {
  onWithdraw:  e => console.log('Withdrawn:', e.amount),
  onCancel:    e => console.log('Cancelled:', e.refundAmount),
  onPause:     e => console.log('Paused at:', e.pausedAt),
  onResume:    e => console.log('Resumed at:', e.resumedAt),
  onTopUp:     e => console.log('Topped up:', e.amount),
  onClawback:  e => console.log('Clawback:', e.amount),
  pollInterval: 3000,  // ms; default 5000
});

sub.unsubscribe();

Only amount (on onWithdraw/onClawback) is real. Every other numeric/timestamp field — totalWithdrawn, remaining, refundAmount, withdrawnSoFar, pausedAt, withdrawable, resumedAt, newBalance — is a hardcoded 0 / 0n placeholder in src/events.ts (dispatchEvent), marked // TODO: parse tuple data. The contracts emit these as multi-value tuples (e.g. stream_withdrawn{ amount, total_withdrawn, remaining }), and the parser doesn't decode tuple ScVals yet — only the single-value case. Don't rely on these fields until that's implemented; re-fetch via client.streams.get(streamId) instead.


client.factory

streamCount() → Promise<bigint>

streamAddress(id) → Promise<string | null>

protocolFeeBps() → Promise<number>


client.governor

config() → Promise<GovernorConfig>

interface GovernorConfig {
  feeBps:             number;
  feeRecipient?:      string;
  minDurationSeconds: number;
  maxRatePerSecond:   bigint;
  factoryAddress?:    string;
}

StreamInfo

interface StreamInfo {
  id:              bigint;
  address:         string;   // DripStream contract address
  sender:          string;
  recipient:       string;
  token:           string;   // asset contract address
  ratePerSecond:   bigint;   // stroops per second
  startTime:       number;   // unix timestamp
  endTime:         number;   // 0 = open-ended
  withdrawn:       bigint;   // stroops already withdrawn
  paused:          boolean;
  pausedAt:        number;   // timestamp of last pause
  cancelled:       boolean;
  clawbackEnabled: boolean;
}

Error Codes

Each contract has its own error-code space — ConduitError.contract tells you which table applies ('stream' | 'factory' | 'governor'). The same numeric code means something different in each one.

StreamErrorCode (err.contract === 'stream')

Code Constant Meaning
1 NotAuthorized Caller is not sender or recipient
2 StreamNotFound Stream ID does not exist
3 StreamCancelled Stream has been cancelled
4 StreamNotStarted Stream has not started yet
5 StreamEnded Stream is past end_time
6 NothingToWithdraw Zero withdrawable balance
7 InsufficientDeposit Deposit < rate_per_sec
8 InvalidTimeRange end_time ≤ start_time
9 AlreadyPaused Stream is already paused
10 NotPaused Stream is not paused
11 ClawbackDisabled Clawback not enabled
12 ArithmeticOverflow Integer overflow
13 PauseThresholdNotMet force_cancel before the 30-day pause threshold elapsed
14 AlreadyInitialized Stream has already been initialized
15 InvalidAmount withdraw/top_up amount must be > 0

FactoryErrorCode (err.contract === 'factory')

Code Constant Meaning
1 NotInitialized Factory hasn't been initialized
2 InvalidDeposit deposit ≤ 0
3 InvalidRate rate_per_sec ≤ 0
4 InvalidTimeRange end_time ≤ start_time
5 InsufficientDeposit Deposit too small for the rate/duration
6 BackdatedStream start_time is in the past
7 AlreadyInitialized Factory has already been initialized
8 RateExceedsMax rate_per_sec exceeds governor's max_rate_per_second
9 DurationTooShort Duration below governor's min_duration_seconds
10 ArithmeticOverflow Integer overflow validating deposit against duration

GovernorErrorCode (err.contract === 'governor')

Code Constant Meaning
1 NotAuthorized Caller is not the current authority
2 InvalidParam Setter argument failed validation
3 AlreadyInitialized Governor has already been initialized

Utility functions

import { toStroops, fromStroops, calculateRate, streamProgress, withdrawableLocal }
  from '@conduit-protocol/sdk/utils';

toStroops('100.5')             // → 1005000000n
fromStroops(1005000000n)       // → '100.5'
calculateRate('1000', 2592000) // → 3858n  stroops/sec
streamProgress(streamInfo)     // → 0.42   (0–1 fraction elapsed)
withdrawableLocal(streamInfo)  // → bigint (client-side estimate, no RPC call)

withdrawableLocal is useful for building live counters without polling the chain on every render tick.


RPC Server Lifecycle

The SDK maintains an internal cache of SorobanRpc.Server instances keyed by URL. Reusing server instances avoids creating new HTTP agents on every RPC call, which reduces TCP/TLS handshake overhead, lowers GC pressure, and improves throughput — particularly for operations like client.streams.list() that issue multiple RPC calls in quick succession.

getServer(rpcUrl)

Returns a cached SorobanRpc.Server for the given URL. Subsequent calls with the same URL return the same instance. This is the recommended way to obtain an RPC server when calling low-level Soroban helpers directly.

import { getServer } from '@conduit-protocol/sdk';

const server = getServer('https://soroban-mainnet.stellar.org');

clearServerCache()

Clears the internal server cache. Useful in test suites between test cases that switch network configurations, or when you need to force a fresh server instance.

import { clearServerCache } from '@conduit-protocol/sdk';

clearServerCache();

Internal usage: All SDK functions that interact with the Soroban RPC (buildContractCallTx, simulateReadOnly, invokeContract, StreamsModule, subscribeToStream, etc.) build their server through an internal wrapper that calls getServer for the cached instance and adds automatic retry-with-backoff on rate-limit errors (HTTP 429/503). Calling getServer yourself gives you the cached-but-unwrapped instance — no automatic retry — so you do not need to call it yourself unless you are using the low-level Soroban helpers directly and want to manage retries on your own.


Fluent Builder API

The SDK provides StreamBuilder and ConduitBatcher to construct and execute stream operations fluently and in batches.

StreamBuilder

A helper class to build stream configurations with method chaining.

Methods

  • token(address: string): this - Sets the Soroban token contract address.
  • sender(address: string): this - Sets the sender address.
  • recipient(address: string): this - Sets the recipient address.
  • amount(val: number): this - Sets the deposit amount in the smallest unit (stroops).
  • build(): StreamConfig - Validates and returns the built stream configuration. Throws if any required field is missing.
import { StreamBuilder } from '@conduit-protocol/sdk';

const stream = new StreamBuilder()
  .token('USDC')
  .sender('GD...')
  .recipient('GB...')
  .amount(1000)
  .build();

ConduitBatcher

A utility class to bundle multiple stream operations with mandatory client-side validation.

Methods

  • static execute(streams: Record<string, unknown>[]): BatchResult - Validates and bundles the list of stream configurations into a single transaction. Returns { success: false, errors: [...] } if validation fails instead of throwing.

Validation Rules:

  • Payload must be a non-null, non-empty array
  • Each array item must be a non-null object
  • Invalid payloads are rejected at the client before submission
import { ConduitBatcher } from '@conduit-protocol/sdk';

const result = ConduitBatcher.execute([stream1, stream2]);
if (!result.success) {
  console.error('Validation errors:', result.errors);
  return;
}
  • static executeAsync(operations: BatchOperation[], signal?: AbortSignal): Promise<BatchResult> - Asynchronously execute a batch with abort signal support.

Throws: ConduitError if batcher is destroyed.