@rehobothfinance/easy-escrow-sdk
v0.1.2
Published
Non-custodial, compliance-ready escrow infrastructure for Stellar (Soroban)
Downloads
340
Maintainers
Readme
easy-escrow-sdk
Official TypeScript SDK for EasyEscrow — a non-custodial, compliance-ready escrow infrastructure built on Stellar using Soroban smart contracts.
DISCLAIMER — TESTING PHASE
This SDK is currently under active development and testing. It has not been audited for production use. Smart contracts are deployed on testnet only and may change without notice.
Use for educational or development purposes only. Do not use with real funds or in production environments. The authors and Rehoboth Finance accept no liability for any loss or damage arising from use of this software.
Features
- No API key required — talks directly to on-chain Soroban contracts via public RPC
- Factory model — one call deploys your own isolated escrow contract instance
- Wallet-friendly — returns unsigned XDR for browser wallets (Freighter, Albedo, etc.)
- Server-friendly — optionally sign server-side with a secret key
- Compliance-ready — pluggable KYC, AML, and FATF Travel Rule hooks (MiCA-aligned)
- Dispute resolution — built-in arbiter flow with on-chain
resolve() - Audit trail — in-memory, file, or custom store; CSV/JSON export
- Fully typed — comprehensive TypeScript interfaces
Deployed Contracts
The factory is pre-deployed and ready to use. No setup required.
Testnet
| Contract | Address |
|---|---|
| EscrowFactory | CBZ7FQU4F7WAMQUPKLAKJEV6TZSTRVMY5AHCEX3PDZVFV5S6OCZWOSWM |
| DisputeRegistry | CCD2EEJKM3GTCFB4ON245C24W353WJ5WAWBQP3GJE6DOZKKD3AB47CKN |
| Escrow WASM hash | b126ba033228b966503d84aae325fd12a3022d205144baea9d97ca17c272ec4f |
View on Stellar Expert:
Mainnet
Mainnet deployment is planned. Track progress in GitHub Issues.
Installation
npm install @rehobothfinance/easy-escrow-sdk @stellar/stellar-sdk@^12.0.0@stellar/stellar-sdk v12.x is required as a peer dependency. Versions above v12 currently break SorobanRpc.Server interop and are not supported.
CommonJS only: Use
require()or set"moduleResolution": "node"in yourtsconfig.json. ESM imports of@stellar/stellar-sdkhave known interop issues at runtime.
Quick Start
import { EscrowClient, SupportedNetworks } from '@rehobothfinance/easy-escrow-sdk';
// Initialize — no API key needed
const escrow = new EscrowClient({ network: SupportedNetworks.TESTNET });
// 1. Deploy a new escrow via the factory (wallet/browser mode)
const result = await escrow.create(
{
payer: 'GPAYER_STELLAR_ADDRESS',
payee: 'GPAYEE_STELLAR_ADDRESS',
asset: 'CXLM_TOKEN_CONTRACT_ADDRESS',
amount: 10_000_000n, // in stroops (1 XLM = 10_000_000)
},
{ type: 'publicKey', publicKey: 'GPAYER_STELLAR_ADDRESS' }
);
if (result.mode === 'xdr') {
// Hand the XDR to your wallet to sign, then submit
const signedXdr = await yourWallet.sign(result.xdr);
await escrow.submitXdr(signedXdr);
}
// 2. Read live on-chain state (no signer needed)
const state = await escrow.getEscrow('CESCROW_CONTRACT_ADDRESS');
console.log(state.status); // "Created" | "Funded" | "Active" | ...
// 3. How many escrows have been deployed via the factory
const count = await escrow.escrowCount();
console.log(`${count} escrows deployed`);Server-side signing
const result = await escrow.create(
{ payer, payee, asset, amount },
{ type: 'secret', secret: process.env.PAYER_SECRET_KEY! }
);
if (result.mode === 'signed') {
console.log('Deployed escrow at:', result.record.id);
console.log('Transaction hash:', result.txHash);
}Escrow Lifecycle
CREATED → FUNDED → ACTIVE → RELEASED
↘ DISPUTED → RESOLVED
↘ REFUNDED// Fund (payer locks tokens in the escrow contract)
await escrow.fund('CESCROW_ADDRESS', payerSigner);
// Payee confirms delivery
await escrow.activate('CESCROW_ADDRESS', payeeSigner);
// Payer releases payment
await escrow.release('CESCROW_ADDRESS', payerSigner);
// Or: payee initiates refund
await escrow.refund('CESCROW_ADDRESS', payeeSigner);
// Or: either party opens a dispute
await escrow.dispute('CESCROW_ADDRESS', initiatorAddress, signerWithPublicKey);
// Arbiter resolves — true = pay payee, false = refund payer
await escrow.resolveDispute('CESCROW_ADDRESS', true, arbiterSigner);Compliance (Optional)
Compliance hooks run before every state transition. Any hook returning { allow: false } blocks the operation.
import { EscrowClient, SupportedNetworks } from '@rehobothfinance/easy-escrow-sdk';
import { DiditIdentityProvider } from '@rehobothfinance/easy-escrow-sdk';
const escrow = new EscrowClient({ network: SupportedNetworks.TESTNET });
// Plug in a KYC provider
escrow.identity.setProvider(
new DiditIdentityProvider({ apiKey: '...', workflowId: '...' })
);
// Add a custom compliance hook
escrow.compliance.register({
async beforeCreate(ctx) {
const profile = await escrow.identity.verify(ctx.params.payer);
if (!profile?.verified) return { allow: false, reason: 'KYC not complete' };
return { allow: true };
},
});Policy Engine
import { MaxAmountPolicy, AllowedAssetsPolicy } from '@rehobothfinance/easy-escrow-sdk';
// Reject escrows over 10 000 XLM
escrow.policy.add(new MaxAmountPolicy(100_000_000_000n));
// Only allow specific asset contracts
escrow.policy.add(new AllowedAssetsPolicy(['CXLM_CONTRACT', 'CUSDC_CONTRACT']));Audit
import { FileAuditStore } from '@rehobothfinance/easy-escrow-sdk';
escrow.setAuditStore(new FileAuditStore('./audit-log.jsonl'));
// Export as CSV
const csv = await escrow.export({ format: 'csv' });
// Query entries
const entries = await escrow.queryAudit({ escrowId: 'CESCROW_ADDRESS' });Supported Networks
| Constant | Network |
|------------------------------|--------------|
| SupportedNetworks.TESTNET | Stellar Testnet |
| SupportedNetworks.MAINNET | Stellar Mainnet |
| SupportedNetworks.FUTURENET| Stellar Futurenet |
| SupportedNetworks.LOCAL | Local node (localhost:8000) |
Custom network:
const escrow = new EscrowClient({
network: {
name: 'testnet',
rpcUrl: 'https://your-rpc-node.example.com',
networkPassphrase: 'Test SDF Network ; September 2015',
contractIds: {
factory: 'CFACTORY_CONTRACT_ADDRESS',
},
},
});TypeScript Types
import {
EscrowClient,
EscrowClientConfig,
SupportedNetworks,
Signer,
TransactionResult,
SignedResult,
XdrResult,
CreateResult,
OnChainEscrowState,
EscrowRecord,
CreateEscrowParams,
} from '@rehobothfinance/easy-escrow-sdk';EscrowStandard
The EscrowStandard type and validateEscrowStandard / toEscrowStandard helpers are exported for cross-platform interoperability. Important field constraints enforced by Zod:
| Field | Type | Notes |
|---|---|---|
| createdAt | string | ISO 8601 datetime — e.g. new Date().toISOString() |
| updatedAt | string | ISO 8601 datetime |
| conditions | Record<string, unknown> | Object, not a string |
| amount | string | Decimal string — e.g. "100.50" |
import { validateEscrowStandard, toEscrowStandard } from '@rehobothfinance/easy-escrow-sdk';
const result = validateEscrowStandard({
version: '1.0.0',
escrowId: 'CESCROW...',
payer: 'GPAYER...',
payee: 'GPAYEE...',
amount: '100.50',
asset: 'XLM',
status: 'Created',
conditions: { deliveryConfirmed: false }, // object, not string
createdAt: new Date().toISOString(), // ISO string, not timestamp number
updatedAt: new Date().toISOString(),
});Building from Source
npm install
npm run build # compile to dist/
npm test # run all tests
npm run typecheck # type-check without emittingArchitecture
- Factory — one pre-deployed
EscrowFactorycontract per network. Callingcreate_escrow()deploys and initializes a freshEscrowContractinstance atomically. - No custody — funds live inside each escrow contract, not in any wallet controlled by EasyEscrow.
- No backend — the SDK speaks directly to Stellar's public Soroban RPC. No API key or server needed for basic use.
- Rust contracts —
contracts/escrowandcontracts/factoryare the on-chain source of truth.
License
Apache-2.0 © EasyEscrow contributors
