npm package: @rehobothfinance/easy-escrow-sdk
Description: Non-custodial, compliance-ready escrow infrastructure for Stellar (Soroban)
Latest version: 0.1.2

# easy-escrow-sdk

[![npm version](https://img.shields.io/npm/v/@rehobothfinance/easy-escrow-sdk)](https://www.npmjs.com/package/@rehobothfinance/easy-escrow-sdk)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)

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:
- [Factory contract](https://stellar.expert/explorer/testnet/contract/CBZ7FQU4F7WAMQUPKLAKJEV6TZSTRVMY5AHCEX3PDZVFV5S6OCZWOSWM)
- [Dispute contract](https://stellar.expert/explorer/testnet/contract/CCD2EEJKM3GTCFB4ON245C24W353WJ5WAWBQP3GJE6DOZKKD3AB47CKN)

### Mainnet

Mainnet deployment is planned. Track progress in [GitHub Issues](https://github.com/Rehoboth-Finance/easy-escrow/issues).

---

## Installation

```bash
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 your `tsconfig.json`. ESM imports of `@stellar/stellar-sdk` have known interop issues at runtime.

---

## Quick Start

```typescript
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

```typescript
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
```

```typescript
// 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.

```typescript
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

```typescript
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

```typescript
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:

```typescript
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

```typescript
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"` |

```typescript
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

```bash
npm install
npm run build       # compile to dist/
npm test            # run all tests
npm run typecheck   # type-check without emitting
```

---

## Architecture

- **Factory** — one pre-deployed `EscrowFactory` contract per network. Calling `create_escrow()` deploys and initializes a fresh `EscrowContract` instance 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/escrow` and `contracts/factory` are the on-chain source of truth.

---

## License

Apache-2.0 © EasyEscrow contributors