@thebarmaeffect/barter-sdk

The official JavaScript/TypeScript SDK for the BARTER Protocol -- a Proof of Trade system for trustless, peer-to-peer commerce on Ethereum with Lightning Network settlement.
Hackathon judges: This SDK builds successfully (npm install && npm run build). All sub-clients (TrustClient, TradeClient, CreditClient, ComplianceClient, WebLNSettler) are fully implemented using ethers.js v6 — not stubs. Contract addresses are placeholder until Sepolia deployment; update src/constants.ts after running npx hardhat run scripts/deploy.ts --network sepolia.
BARTER enables on-chain trade proposals secured by Lightning payment hashes, on-chain trust scores derived from trade history, credit line management between counterparties, and compliance anomaly detection -- all accessible through a single, type-safe client.
Table of Contents
Features
- Trust Scores -- Query on-chain trust scores, full profiles, score history, and pairwise trust between any two addresses.
- Trade Lifecycle -- Propose, accept, settle, and query trades with full type safety and event parsing.
- Credit Lines -- Extend, revoke, and query credit lines between counterparties with interest rate and expiration support.
- Compliance -- Detect anomaly flags, velocity anomalies, and generate full compliance reports with risk-level classification.
- WebLN / Lightning -- Pay invoices and create invoices directly from the browser via Alby or any WebLN-compatible wallet.
- TypeScript-First -- Every method, parameter, and return value is fully typed. Ship with confidence.
- Dual Module Format -- Ships both CommonJS and ESM builds with full tree-shaking support.
- Ethers v6 -- Built on ethers.js v6 for modern, lightweight Ethereum interaction.
Installation
npm install @thebarmaeffect/barter-sdk ethers
yarn add @thebarmaeffect/barter-sdk ethers
pnpm add @thebarmaeffect/barter-sdk ethers
Peer Dependencies
ethers | ^6.0.0 | Ethereum provider, signers, ABIs |
Note: ethers is a peer dependency and must be installed alongside the SDK.
Quick Start
Read-Only Queries (Browser or Node.js)
Connect with just an RPC URL to read trust scores, trade data, and compliance information. No signer required.
import { BarterClient } from '@thebarmaeffect/barter-sdk';
const client = new BarterClient({
rpcUrl: 'https://rpc.sepolia.org',
network: 'sepolia',
});
const score = await client.trust.getScore('0xAbC123...def456');
console.log(`Trust score: ${score}`);
const profile = await client.trust.getProfile('0xAbC123...def456');
console.log(`Trades completed: ${profile.tradeCount}`);
console.log(`Completion rate: ${(profile.completionRate * 100).toFixed(1)}%`);
console.log(`Unique counterparties: ${profile.uniqueCounterparties}`);
const report = await client.compliance.getComplianceReport('0xAbC123...def456');
console.log(`Risk level: ${report.riskLevel}`);
Full Trade Lifecycle (Node.js with Signer)
Use a signer to propose, accept, and settle trades.
import { ethers } from 'ethers';
import { BarterClient, TradeStatus } from '@thebarmaeffect/barter-sdk';
const provider = new ethers.JsonRpcProvider('https://rpc.sepolia.org');
const signer = new ethers.Wallet('0xYOUR_PRIVATE_KEY', provider);
const client = new BarterClient({
provider,
signer,
network: 'sepolia',
});
const tradeId = await client.trade.propose(
'0xCounterpartyAddress',
'0xPaymentHash...',
50_000,
'goods',
'Widget purchase order #42',
);
console.log(`Trade proposed: ${tradeId}`);
await client.trade.accept(tradeId);
await client.trade.settle(tradeId, '0xPreimage64HexChars...');
const trade = await client.trade.getTrade(tradeId);
console.log(`Status: ${TradeStatus[trade.status]}`);
Browser with WebLN (Lightning via Alby)
Settle trades using a Lightning wallet directly in the browser.
import { BarterClient } from '@thebarmaeffect/barter-sdk';
const client = new BarterClient({
rpcUrl: 'https://rpc.sepolia.org',
network: 'sepolia',
});
if (client.webln.isAvailable()) {
const { paymentRequest } = await client.webln.makeInvoice(
50_000,
'BARTER trade settlement',
);
console.log(`Invoice: ${paymentRequest}`);
const { preimage } = await client.webln.pay(paymentRequest);
console.log(`Preimage: ${preimage}`);
await client.trade.settle(tradeId, preimage);
} else {
console.log('Install Alby to use Lightning payments: https://getalby.com');
}
API Reference
BarterClient
The main entry point. Instantiates all sub-clients and manages the provider, signer, and network configuration.
Constructor
new BarterClient(options?: BarterClientOptions)
BarterClientOptions
rpcUrl | string | 'https://rpc.sepolia.org' | JSON-RPC endpoint URL |
network | string | 'sepolia' | Network name. Must match a key in CONTRACTS |
signer | ethers.Signer | null | Signer for write operations (propose, accept, settle) |
provider | ethers.Provider | Created from rpcUrl | Custom provider instance (overrides rpcUrl) |
Resolution order for provider: If provider is supplied, it is used directly. Otherwise, if rpcUrl is supplied, a JsonRpcProvider is created. Otherwise, the default Sepolia RPC is used.
Throws: Error if network does not match any entry in the CONTRACTS mapping.
Properties
trust | TrustClient | Trust score and profile queries |
trade | TradeClient | Trade lifecycle management |
credit | CreditClient | Credit line management |
compliance | ComplianceClient | Anomaly detection and compliance |
webln | WebLNSettler | WebLN Lightning payment integration |
Methods
getProvider()
getProvider(): ethers.Provider
Returns the active Ethereum provider instance.
getSigner()
getSigner(): ethers.Signer | null
Returns the active signer, or null if no signer was provided.
getNetwork()
getNetwork(): string
Returns the configured network name (e.g., 'sepolia').
Example
import { ethers } from 'ethers';
import { BarterClient } from '@thebarmaeffect/barter-sdk';
const readClient = new BarterClient({
rpcUrl: 'https://rpc.sepolia.org',
});
const browserProvider = new ethers.BrowserProvider(window.ethereum);
const signer = await browserProvider.getSigner();
const writeClient = new BarterClient({
provider: browserProvider,
signer,
network: 'sepolia',
});
TrustClient
Query on-chain trust scores, full profiles, score history, and pairwise trust. All methods are read-only and do not require a signer.
Access via client.trust.
getScore(address)
Retrieve the current trust score for an address.
getScore(address: string): Promise<number>
Parameters
address | string | Ethereum address to query |
Returns: Promise<number> -- The trust score as an integer.
Throws:
InvalidAddressError if address is not a valid Ethereum address.
Error if the BTRTrust contract is not initialized.
Example
const score = await client.trust.getScore('0xAbC123...def456');
console.log(`Trust score: ${score}`);
getProfile(address)
Retrieve the full trust profile for an address, including trade count, completion rate, counterparty count, and timestamps.
getProfile(address: string): Promise<TrustProfile>
Parameters
address | string | Ethereum address to query |
Returns: Promise<TrustProfile> -- See TrustProfile for field descriptions.
Throws:
InvalidAddressError if address is not a valid Ethereum address.
Error if the BTRTrust contract is not initialized.
Example
const profile = await client.trust.getProfile('0xAbC123...def456');
console.log(`Score: ${profile.score}`);
console.log(`Trades: ${profile.tradeCount}`);
console.log(`Completion rate: ${(profile.completionRate * 100).toFixed(1)}%`);
console.log(`Unique counterparties: ${profile.uniqueCounterparties}`);
if (profile.memberSince) {
console.log(`Member since: ${profile.memberSince.toISOString()}`);
}
getScoreHistory(address, fromBlock?)
Query the history of trust score changes for an address by reading ScoreUpdated events from the chain.
getScoreHistory(address: string, fromBlock?: number): Promise<ScoreEvent[]>
Parameters
address | string | -- | Ethereum address to query |
fromBlock | number | 0 | Block number to start scanning from |
Returns: Promise<ScoreEvent[]> -- Array of score change events. See ScoreEvent.
Throws:
InvalidAddressError if address is not a valid Ethereum address.
Error if the BTRTrust contract is not initialized.
Example
const history = await client.trust.getScoreHistory('0xAbC123...def456', 5_000_000);
for (const event of history) {
const direction = event.delta > 0 ? '+' : '';
console.log(
`Block ${event.blockNumber}: ${direction}${event.delta} -> ${event.newScore} ` +
`(${event.amountSats} sats with ${event.counterparty})`
);
}
getPairTrust(addressA, addressB)
Get the pairwise trust score between two addresses. This reflects the strength of the direct trading relationship between them.
getPairTrust(addressA: string, addressB: string): Promise<number>
Parameters
addressA | string | First Ethereum address |
addressB | string | Second Ethereum address |
Returns: Promise<number> -- Pairwise trust score (0 to MAX_PAIR_TRUST, which is 5).
Throws:
InvalidAddressError if either address is invalid.
Error if the BTRTrust contract is not initialized.
Example
const pairTrust = await client.trust.getPairTrust(
'0xAlice...',
'0xBob...',
);
console.log(`Pair trust: ${pairTrust} / ${5}`);
TradeClient
Manage the full trade lifecycle: propose, accept, settle, and query trades. Write operations (propose, accept, settle) require a signer.
Access via client.trade.
propose(partyB, paymentHash, amountSats, category?, description?)
Propose a new trade to a counterparty. Submits a transaction to the BarterCore contract and returns the trade ID from the emitted TradeProposed event.
propose(
partyB: string,
paymentHash: string,
amountSats: number,
category?: string,
description?: string,
): Promise<string>
Parameters
partyB | string | -- | Counterparty Ethereum address |
paymentHash | string | -- | Lightning payment hash (hex string) |
amountSats | number | -- | Trade amount in satoshis (minimum: 1,000) |
category | string | 'general' | Trade category label |
description | string | '' | Human-readable trade description |
Returns: Promise<string> -- The unique trade ID emitted by the TradeProposed event.
Throws:
InvalidAddressError if partyB is not a valid Ethereum address.
InsufficientAmountError if amountSats is below MIN_TRADE_SATS (1,000).
SelfTradeError if the signer's address equals partyB.
Error if no signer is configured or the contract is not initialized.
Example
const tradeId = await client.trade.propose(
'0xCounterparty...',
'0xabc123...payment_hash_64_hex_chars',
50_000,
'services',
'Logo design - milestone 1',
);
console.log(`Trade proposed: ${tradeId}`);
accept(tradeId)
Accept a proposed trade. Must be called by the partyB of the trade.
accept(tradeId: string): Promise<void>
Parameters
tradeId | string | The trade ID to accept |
Returns: Promise<void>
Throws:
Error if no signer is configured or the contract is not initialized.
Example
await client.trade.accept('0xTradeId...');
console.log('Trade accepted');
settle(tradeId, preimage)
Settle a trade by providing the Lightning payment preimage. The contract verifies the preimage matches the trade's payment hash before finalizing.
settle(tradeId: string, preimage: string): Promise<void>
Parameters
tradeId | string | The trade ID to settle |
preimage | string | Payment preimage, 32-byte hex (0x + 64 hex chars) |
Returns: Promise<void>
Throws:
PreimageMismatchError if preimage is not a valid 32-byte hex string (must match /^0x[0-9a-fA-F]{64}$/).
Error if no signer is configured or the contract is not initialized.
Example
await client.trade.settle(
'0xTradeId...',
'0x4a5b6c7d8e9f...preimage_64_hex_chars',
);
console.log('Trade settled');
getTrade(tradeId)
Fetch the details of a specific trade by its ID.
getTrade(tradeId: string): Promise<Trade>
Parameters
tradeId | string | The trade ID to look up |
Returns: Promise<Trade> -- See Trade for field descriptions.
Throws:
TradeNotFoundError if no trade exists with the given ID.
Error if the contract is not initialized.
Example
import { TradeStatus } from '@thebarmaeffect/barter-sdk';
const trade = await client.trade.getTrade('0xTradeId...');
console.log(`Party A: ${trade.partyA}`);
console.log(`Party B: ${trade.partyB}`);
console.log(`Amount: ${trade.amountSats} sats`);
console.log(`Status: ${TradeStatus[trade.status]}`);
console.log(`Created: ${trade.createdAt.toISOString()}`);
listTrades(address?, status?, limit?, offset?)
List trades, optionally filtered by address and/or status, with pagination.
listTrades(
address?: string,
status?: TradeStatus,
limit?: number,
offset?: number,
): Promise<Trade[]>
Parameters
address | string | -- | Filter trades involving this address |
status | TradeStatus | -- | Filter by trade status |
limit | number | 50 | Maximum number of trades to return |
offset | number | 0 | Number of trades to skip (for pagination) |
Returns: Promise<Trade[]> -- Array of trades matching the filters.
Throws:
InvalidAddressError if address is provided but invalid.
Error if the contract is not initialized.
Example
import { TradeStatus } from '@thebarmaeffect/barter-sdk';
const trades = await client.trade.listTrades('0xMyAddress...');
const settled = await client.trade.listTrades(
'0xMyAddress...',
TradeStatus.Settled,
20,
0,
);
for (const t of settled) {
console.log(`${t.tradeId}: ${t.amountSats} sats - ${TradeStatus[t.status]}`);
}
CreditClient
Manage credit lines between counterparties. Credit lines allow trusted parties to trade up to a specified limit with optional interest rates and expiration.
Access via client.credit.
getCreditLine(creditor, debtor)
Fetch the credit line between a creditor and debtor.
getCreditLine(creditor: string, debtor: string): Promise<CreditLine>
Parameters
creditor | string | Address of the credit extender |
debtor | string | Address of the credit receiver |
Returns: Promise<CreditLine>
interface CreditLine {
creditor: string;
debtor: string;
limitSats: number;
usedSats: number;
availableSats: number;
interestBps: number;
expiresAt: Date | null;
}
Throws:
InvalidAddressError if either address is invalid.
Error if the BTRCredit contract is not initialized.
Example
const line = await client.credit.getCreditLine('0xCreditor...', '0xDebtor...');
console.log(`Limit: ${line.limitSats} sats`);
console.log(`Used: ${line.usedSats} sats`);
console.log(`Available: ${line.availableSats} sats`);
console.log(`Interest: ${line.interestBps / 100}%`);
extendCredit(debtor, limitSats, interestBps?, durationSeconds?)
Extend a credit line to another address. Requires a signer.
extendCredit(
debtor: string,
limitSats: number,
interestBps?: number,
durationSeconds?: number,
): Promise<void>
Parameters
debtor | string | -- | Address to extend credit to |
limitSats | number | -- | Maximum credit limit in satoshis |
interestBps | number | 0 | Interest rate in basis points (100 bps = 1%) |
durationSeconds | number | 0 | Duration in seconds (0 = no expiration) |
Returns: Promise<void>
Throws:
InvalidAddressError if debtor is not a valid address.
Error if no signer is configured or the contract is not initialized.
Example
await client.credit.extendCredit(
'0xDebtor...',
100_000,
200,
30 * 24 * 3600,
);
revokeCredit(debtor)
Revoke a previously extended credit line. Requires a signer.
revokeCredit(debtor: string): Promise<void>
Parameters
debtor | string | Address whose credit to revoke |
Returns: Promise<void>
Throws:
InvalidAddressError if debtor is not a valid address.
Error if no signer is configured or the contract is not initialized.
Example
await client.credit.revokeCredit('0xDebtor...');
console.log('Credit line revoked');
getActiveCreditLines(address)
Fetch all active credit lines involving an address (both as creditor and debtor).
getActiveCreditLines(address: string): Promise<CreditLine[]>
Parameters
address | string | Address to query credit lines for |
Returns: Promise<CreditLine[]>
Throws:
InvalidAddressError if address is not valid.
Error if the BTRCredit contract is not initialized.
Example
const lines = await client.credit.getActiveCreditLines('0xMyAddress...');
for (const line of lines) {
console.log(`${line.creditor} -> ${line.debtor}: ${line.availableSats} sats available`);
}
getTotalCreditExtended(address)
Get the total amount of credit extended by an address across all credit lines.
getTotalCreditExtended(address: string): Promise<number>
Parameters
address | string | Address to query |
Returns: Promise<number> -- Total credit extended in satoshis.
Throws:
InvalidAddressError if address is not valid.
Error if the BTRCredit contract is not initialized.
getTotalCreditReceived(address)
Get the total amount of credit received by an address across all credit lines.
getTotalCreditReceived(address: string): Promise<number>
Parameters
address | string | Address to query |
Returns: Promise<number> -- Total credit received in satoshis.
Throws:
InvalidAddressError if address is not valid.
Error if the BTRCredit contract is not initialized.
ComplianceClient
Detect anomalous trading behavior, check velocity metrics, and generate compliance reports. All methods are read-only.
Access via client.compliance.
getFlags(address)
Retrieve all anomaly flags for an address. Flags indicate potentially suspicious patterns detected by the protocol's on-chain compliance module.
getFlags(address: string): Promise<AnomalyFlag[]>
Parameters
address | string | Ethereum address to query |
Returns: Promise<AnomalyFlag[]> -- See AnomalyFlag for field descriptions.
Throws:
InvalidAddressError if address is not a valid Ethereum address.
Error if the BarterCore contract is not initialized.
Example
const flags = await client.compliance.getFlags('0xSuspect...');
for (const flag of flags) {
console.log(`[${flag.severity.toUpperCase()}] ${flag.flagType}: ${flag.description}`);
console.log(` Detected: ${flag.detectedAt.toISOString()}`);
}
getVelocity(address)
Fetch the trading velocity report for an address. Velocity metrics track trading frequency and average amounts over recent time windows.
getVelocity(address: string): Promise<VelocityReport>
Parameters
address | string | Ethereum address to query |
Returns: Promise<VelocityReport> -- See VelocityReport for field descriptions.
Throws:
InvalidAddressError if address is not a valid Ethereum address.
Error if the BarterCore contract is not initialized.
Example
const velocity = await client.compliance.getVelocity('0xTrader...');
console.log(`Trades (24h): ${velocity.trades24h}`);
console.log(`Trades (7d): ${velocity.trades7d}`);
console.log(`Trades (30d): ${velocity.trades30d}`);
console.log(`Avg amount: ${velocity.avgAmountSats} sats`);
console.log(`Elevated: ${velocity.isElevated}`);
getComplianceReport(address)
Generate a full compliance report combining anomaly flags and velocity data, with an automatically calculated risk level.
Risk level calculation:
'high' -- Any high-severity flags exist, OR velocity is elevated.
'medium' -- Any medium-severity flags exist (no high flags, velocity not elevated).
'low' -- No medium or high flags and velocity is normal.
getComplianceReport(address: string): Promise<ComplianceReport>
Parameters
address | string | Ethereum address to query |
Returns: Promise<ComplianceReport> -- See ComplianceReport for field descriptions.
Throws:
InvalidAddressError if address is not a valid Ethereum address.
Example
const report = await client.compliance.getComplianceReport('0xTrader...');
console.log(`Risk Level: ${report.riskLevel.toUpperCase()}`);
console.log(`Flags: ${report.flags.length}`);
console.log(`Trades (30d): ${report.velocity.trades30d}`);
console.log(`Report generated: ${report.generatedAt.toISOString()}`);
if (report.riskLevel === 'high') {
console.warn('HIGH RISK - review required');
}
WebLNSettler
Browser-side Lightning Network integration via the WebLN standard. Supports any WebLN-compatible wallet (Alby, Zeus, etc.).
Access via client.webln.
isAvailable()
Check whether a WebLN provider is available in the current browser environment.
isAvailable(): boolean
Returns: boolean -- true if window.webln exists, false otherwise (including in Node.js).
Example
if (client.webln.isAvailable()) {
console.log('Lightning wallet detected');
} else {
console.log('No Lightning wallet found');
}
pay(invoice)
Pay a Lightning invoice and return the preimage. Enables the WebLN provider before sending.
pay(invoice: string): Promise<{ preimage: string }>
Parameters
invoice | string | BOLT11-encoded Lightning invoice |
Returns: Promise<{ preimage: string }> -- The payment preimage, which can be used to settle an on-chain trade.
Throws:
BarterError if WebLN is not available.
Example
const { preimage } = await client.webln.pay('lnbc500u1p...');
await client.trade.settle(tradeId, preimage);
makeInvoice(amountSats, memo?)
Create a Lightning invoice via the WebLN provider.
makeInvoice(amountSats: number, memo?: string): Promise<{ paymentRequest: string }>
Parameters
amountSats | number | -- | Invoice amount in satoshis |
memo | string | 'BARTER trade' | Invoice memo / description |
Returns: Promise<{ paymentRequest: string }> -- BOLT11-encoded invoice string.
Throws:
BarterError if WebLN is not available.
Example
const { paymentRequest } = await client.webln.makeInvoice(50_000, 'Payment for order #42');
console.log(`Invoice: ${paymentRequest}`);
TypeScript Types
All types are exported from the package root:
import {
TradeStatus,
type TrustProfile,
type Trade,
type ScoreEvent,
type AnomalyFlag,
type VelocityReport,
type ComplianceReport,
} from '@thebarmaeffect/barter-sdk';
TradeStatus
Enum representing the lifecycle state of a trade.
enum TradeStatus {
Proposed = 0,
Accepted = 1,
Settled = 2,
Disputed = 3,
Expired = 4,
}
TrustProfile
Full on-chain trust profile for an address.
interface TrustProfile {
address: string;
score: number;
uniqueCounterparties: number;
memberSince: Date | null;
tradeCount: number;
completionRate: number;
lastTradeAt: Date | null;
}
Trade
Represents a single trade on the BarterCore contract.
interface Trade {
tradeId: string;
partyA: string;
partyB: string;
paymentHash: string;
amountSats: number;
status: TradeStatus;
createdAt: Date;
acceptedAt: Date | null;
settledAt: Date | null;
category: string;
description: string;
}
ScoreEvent
A single trust score change event from the chain.
interface ScoreEvent {
blockNumber: number;
timestamp: Date;
delta: number;
newScore: number;
counterparty: string;
amountSats: number;
}
AnomalyFlag
An anomaly flag detected by the compliance module.
interface AnomalyFlag {
flagType: string;
severity: 'low' | 'medium' | 'high';
description: string;
detectedAt: Date;
}
VelocityReport
Trading velocity metrics across multiple time windows.
interface VelocityReport {
address: string;
trades24h: number;
trades7d: number;
trades30d: number;
avgAmountSats: number;
isElevated: boolean;
}
ComplianceReport
Combined compliance report with risk classification.
interface ComplianceReport {
address: string;
flags: AnomalyFlag[];
velocity: VelocityReport;
riskLevel: 'low' | 'medium' | 'high';
generatedAt: Date;
}
CreditLine
A credit line between two counterparties.
interface CreditLine {
creditor: string;
debtor: string;
limitSats: number;
usedSats: number;
availableSats: number;
interestBps: number;
expiresAt: Date | null;
}
Error Handling
All SDK errors extend from BarterError, making it easy to catch SDK-specific errors separately from network or provider errors.
import {
BarterError,
InvalidAddressError,
TradeNotFoundError,
PreimageMismatchError,
InsufficientAmountError,
SelfTradeError,
} from '@thebarmaeffect/barter-sdk';
Error Hierarchy
Error
└── BarterError Base class for all SDK errors
├── InvalidAddressError Address failed ethers.isAddress() validation
├── TradeNotFoundError No trade exists with the given ID
├── PreimageMismatchError Preimage is not valid 32-byte hex
├── InsufficientAmountError Trade amount below MIN_TRADE_SATS (1,000)
└── SelfTradeError Attempted to trade with own address
BarterError
Base error class. All other SDK errors inherit from this.
class BarterError extends Error {
name: 'BarterError';
}
InvalidAddressError
Thrown when an Ethereum address fails validation via ethers.isAddress().
class InvalidAddressError extends BarterError {
name: 'InvalidAddressError';
}
TradeNotFoundError
Thrown when getTrade() is called with a trade ID that does not exist on-chain.
class TradeNotFoundError extends BarterError {
name: 'TradeNotFoundError';
}
PreimageMismatchError
Thrown when the preimage passed to settle() does not match the expected format (/^0x[0-9a-fA-F]{64}$/).
class PreimageMismatchError extends BarterError {
name: 'PreimageMismatchError';
}
InsufficientAmountError
Thrown when the amountSats passed to propose() is below MIN_TRADE_SATS (1,000 sats).
class InsufficientAmountError extends BarterError {
name: 'InsufficientAmountError';
}
SelfTradeError
Thrown when the signer's address matches the partyB address in propose().
class SelfTradeError extends BarterError {
name: 'SelfTradeError';
}
Catching Errors
import { BarterError, InvalidAddressError, TradeNotFoundError } from '@thebarmaeffect/barter-sdk';
try {
const trade = await client.trade.getTrade('0xNonExistent...');
} catch (error) {
if (error instanceof TradeNotFoundError) {
console.log('Trade does not exist');
} else if (error instanceof InvalidAddressError) {
console.log('Bad address format');
} else if (error instanceof BarterError) {
console.log(`SDK error: ${error.message}`);
} else {
throw error;
}
}
WebLN Integration
WebLN is a browser standard for interacting with Lightning Network wallets. The BARTER SDK uses WebLN to bridge on-chain trade proposals with off-chain Lightning payments.
How It Works
- User installs a WebLN wallet -- Alby is the most popular browser extension. Other compatible wallets include Zeus and BlueWallet.
- SDK detects the wallet via
window.webln.
makeInvoice() creates a Lightning invoice through the user's wallet.
pay() sends a Lightning payment and returns the preimage.
- Preimage settles the on-chain trade via
client.trade.settle().
Browser Detection and Fallback
const client = new BarterClient({ rpcUrl: 'https://rpc.sepolia.org' });
async function settleWithLightning(tradeId: string, invoice: string) {
if (client.webln.isAvailable()) {
const { preimage } = await client.webln.pay(invoice);
await client.trade.settle(tradeId, preimage);
return { method: 'webln', preimage };
}
console.log('No Lightning wallet detected.');
console.log('Please pay this invoice manually and provide the preimage:');
console.log(invoice);
return { method: 'manual', invoice };
}
Full WebLN Trade Flow
const { paymentRequest } = await client.webln.makeInvoice(
trade.amountSats,
`BARTER trade ${trade.tradeId}`,
);
const { preimage } = await client.webln.pay(paymentRequest);
await client.trade.settle(trade.tradeId, preimage);
Framework Integration
React
Use with the companion package @thebarmaeffect/barter-react for hooks and context:
import { BarterProvider, useBarterScore } from '@thebarmaeffect/barter-react';
function App() {
return (
<BarterProvider config={{ rpcUrl: 'https://rpc.sepolia.org', network: 'sepolia' }}>
<TrustBadge address="0x..." />
</BarterProvider>
);
}
function TrustBadge({ address }: { address: string }) {
const { data: score, loading, error } = useBarterScore(address);
if (loading) return <span>Loading...</span>;
if (error) return <span>Error</span>;
return <span>Trust: {score}</span>;
}
Next.js
The SDK works in both Server Components (read-only) and Client Components (full functionality).
import { BarterClient } from '@thebarmaeffect/barter-sdk';
const client = new BarterClient({
rpcUrl: process.env.RPC_URL,
network: 'sepolia',
});
export async function GET(
request: Request,
{ params }: { params: { address: string } },
) {
const profile = await client.trust.getProfile(params.address);
return Response.json(profile);
}
'use client';
import { useState } from 'react';
import { ethers } from 'ethers';
import { BarterClient } from '@thebarmaeffect/barter-sdk';
export function TradeForm() {
const [tradeId, setTradeId] = useState('');
async function handlePropose() {
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const client = new BarterClient({ provider, signer, network: 'sepolia' });
const id = await client.trade.propose(
'0xCounterparty...',
'0xPaymentHash...',
50_000,
);
setTradeId(id);
}
return (
<div>
<button onClick={handlePropose}>Propose Trade</button>
{tradeId && <p>Trade ID: {tradeId}</p>}
</div>
);
}
Vue 3
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { BarterClient } from '@thebarmaeffect/barter-sdk';
const client = new BarterClient({
rpcUrl: 'https://rpc.sepolia.org',
network: 'sepolia',
});
const score = ref<number | null>(null);
const loading = ref(true);
onMounted(async () => {
try {
score.value = await client.trust.getScore('0xAbC123...def456');
} finally {
loading.value = false;
}
});
</script>
<template>
<div v-if="loading">Loading trust score...</div>
<div v-else>Trust Score: {{ score }}</div>
</template>
Node.js Server
import { BarterClient, TradeStatus } from '@thebarmaeffect/barter-sdk';
const client = new BarterClient({
rpcUrl: process.env.RPC_URL || 'https://rpc.sepolia.org',
network: 'sepolia',
});
app.get('/api/trades/:address', async (req, res) => {
try {
const trades = await client.trade.listTrades(
req.params.address,
undefined,
parseInt(req.query.limit as string) || 50,
parseInt(req.query.offset as string) || 0,
);
res.json(trades);
} catch (error) {
if (error instanceof BarterError) {
res.status(400).json({ error: error.message });
} else {
res.status(500).json({ error: 'Internal server error' });
}
}
});
Configuration
Network Selection
The network parameter determines which contract addresses are used. Currently supported:
sepolia | 11155111 | Ethereum Sepolia testnet (default) |
const client = new BarterClient({ network: 'sepolia' });
Custom RPC Endpoint
const client = new BarterClient({
rpcUrl: 'https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY',
});
const client = new BarterClient({
rpcUrl: 'https://sepolia.infura.io/v3/YOUR_KEY',
});
const client = new BarterClient({
rpcUrl: 'http://localhost:8545',
});
Custom Provider
import { ethers } from 'ethers';
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const client = new BarterClient({
provider,
signer,
network: 'sepolia',
});
Signer Setup
Write operations require a signer. Several approaches:
import { ethers } from 'ethers';
const provider = new ethers.JsonRpcProvider('https://rpc.sepolia.org');
const signer = new ethers.Wallet('0xPRIVATE_KEY', provider);
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
Constants
Exported constants for reference:
import {
SEPOLIA_CHAIN_ID,
MIN_TRADE_SATS,
MAX_PAIR_TRUST,
TRADE_EXPIRY,
CONTRACTS,
} from '@thebarmaeffect/barter-sdk';
Bundle Size
The SDK ships dual-format builds optimized for both server and browser environments:
| CJS | dist/index.js | CommonJS for Node.js require() |
| ESM | dist/index.mjs | ES Modules for bundlers and modern Node |
| Types | dist/index.d.ts | TypeScript declarations |
Built with tsup, the ESM build supports tree-shaking. If you only use TrustClient, your bundler can eliminate unused trade, credit, and compliance code.
import { TrustClient } from '@thebarmaeffect/barter-sdk';
Development
Prerequisites
- Node.js >= 18
- npm, yarn, or pnpm
Setup
git clone https://github.com/TheBarmaEffect/barter-protocol.git
cd barter-protocol/sdk-js
npm install
Commands
npm run build
npm test
npm run lint
Running Tests
Tests use Jest with ts-jest:
npm test
Contributing
- Fork the repository.
- Create a feature branch:
git checkout -b feat/my-feature
- Make your changes and add tests.
- Ensure all tests pass:
npm test
- Ensure type-checking passes:
npm run lint
- Submit a pull request.
License
MIT -- see LICENSE for details.