zende-sdk
v0.1.3
Published
TypeScript SDK for the Zendetsu escrow protocol on Solana
Readme
zende-sdk
TypeScript SDK for the Zendetsu escrow protocol on Solana.
Trustless escrow for Solana developers. Lock funds, set conditions, release on-chain. No middlemen, no custodians, no trust required.
Install
npm install zende-sdkQuick Start
import { ZendetsuClient, solToLamports } from "zende-sdk";
import { AnchorProvider } from "@coral-xyz/anchor";
const provider = AnchorProvider.env();
// English error messages (default)
const client = new ZendetsuClient(provider);
// Nigerian Pidgin error messages
const client = new ZendetsuClient(provider, { lang: "pidgin" });The IDL is bundled inside the SDK. You do not need to fetch or import it separately.
Error Messages
Every method returns a clean, human-readable error message when something goes wrong. Pass lang: "pidgin" to get Nigerian Pidgin error messages instead of English.
// English (default)
const client = new ZendetsuClient(provider);
try {
await client.confirmRelease(params);
} catch (err) {
console.error(err.message);
// "Escrow is frozen due to an active dispute"
}
// Pidgin
const client = new ZendetsuClient(provider, { lang: "pidgin" });
try {
await client.confirmRelease(params);
} catch (err) {
console.error(err.message);
// "The escrow don freeze, dispute dey ground, wait for resolution"
}Create an Escrow
import BN from "bn.js";
const { escrowId, signature } = await client.createEscrow({
amount: solToLamports(1), // 1 SOL to recipient
feeAmount: solToLamports(0.01), // 0.01 SOL platform fee
mode: { simple: {} },
releaseCondition: { majority: {} },
speed: { standard: {} },
recipient: recipientPublicKey,
treasury: treasuryPublicKey,
});
// Save escrowId — you need it for every subsequent call
console.log("Escrow created:", signature);Confirm and Release
Both parties call confirmRelease. When both confirm, SOL releases instantly.
// Depositor confirms
await client.confirmRelease({
escrowId,
depositor: depositorPublicKey,
recipient: recipientPublicKey,
treasury: treasuryPublicKey,
});
// Recipient confirms — triggers instant release
await client.confirmRelease({
escrowId,
depositor: depositorPublicKey,
recipient: recipientPublicKey,
treasury: treasuryPublicKey,
});Claim After Timelock
await client.claimRelease({
escrowId,
depositor: depositorPublicKey,
treasury: treasuryPublicKey,
});Cancel (Before Recipient Joins)
await client.cancelEscrow({
escrowId,
recipient: recipientPublicKey,
});Milestone Escrow
const { escrowId } = await client.createEscrow({
amount: solToLamports(3),
feeAmount: solToLamports(0.03),
mode: { milestone: {} },
releaseCondition: { majority: {} },
speed: { standard: {} },
recipient: recipientPublicKey,
treasury: treasuryPublicKey,
milestones: [
{ label: "Design mockups", percentage: 30, deadline: new BN(Math.floor(Date.now() / 1000) + 86400 * 7) },
{ label: "Frontend build", percentage: 40, deadline: new BN(Math.floor(Date.now() / 1000) + 86400 * 21) },
{ label: "Final delivery", percentage: 30, deadline: new BN(Math.floor(Date.now() / 1000) + 86400 * 30) },
],
});
// Approve milestone 0 — releases 30% of funds
await client.approveMilestone({
escrowId,
depositor: depositorPublicKey,
recipient: recipientPublicKey,
treasury: treasuryPublicKey,
milestoneIndex: 0,
});
// Reject milestone — 3 rejections auto-escalates to dispute
await client.rejectMilestone({
escrowId,
depositor: depositorPublicKey,
milestoneIndex: 1,
});Timed Release
const releaseAt = new BN(Math.floor(Date.now() / 1000) + 86400 * 30); // 30 days
const { escrowId } = await client.createEscrow({
amount: solToLamports(2),
feeAmount: solToLamports(0.02),
mode: { timed: {} },
releaseCondition: { majority: {} },
speed: { standard: {} },
releaseAt,
recipient: recipientPublicKey,
treasury: treasuryPublicKey,
});Disputes
// Raise a dispute — freezes the escrow
await client.disputeEscrow({
escrowId,
depositor: depositorPublicKey,
});
// Authority resolves — full to recipient
await client.resolveDispute({
escrowId,
depositor: depositorPublicKey,
recipient: recipientPublicKey,
treasury: treasuryPublicKey,
verdict: { recipient: {} },
});
// Authority resolves — 60% to recipient, 40% back to depositor
await client.resolveDispute({
escrowId,
depositor: depositorPublicKey,
recipient: recipientPublicKey,
treasury: treasuryPublicKey,
verdict: { partial: { percentage: 60 } },
});Keep Alive (Ping)
await client.ping({
escrowId,
depositor: depositorPublicKey,
});Fetch Escrow State
const escrow = await client.fetchEscrow(depositorPublicKey, escrowId);
console.log(escrow.status); // { active: {} }
console.log(escrow.amount); // BN (lamports)
const myEscrows = await client.fetchEscrowsByDepositor(depositorPublicKey);
const incoming = await client.fetchEscrowsByRecipient(recipientPublicKey);Utility Functions
import {
solToLamports,
lamportsToSol,
getTimelockForAmount,
isTimelockExpired,
isReleaseReady,
validateMilestones,
formatTimestamp,
parseZendetsuError,
getAllErrorMessages,
} from "zende-sdk";
solToLamports(1.5) // BN(1_500_000_000)
lamportsToSol(new BN(1_000_000_000)) // 1
getTimelockForAmount(solToLamports(0.5)) // 3600 (1 hour)
getTimelockForAmount(solToLamports(5)) // 21600 (6 hours)
getTimelockForAmount(solToLamports(50)) // 86400 (24 hours)
getTimelockForAmount(solToLamports(500)) // 259200 (72 hours)
isTimelockExpired(escrow.timelockUntil) // true / false
isReleaseReady(escrow.releaseAt) // true / false (Timed mode)
formatTimestamp(escrow.createdAt) // "4/23/2026, 2:30:00 AM"
// Parse any error manually
parseZendetsuError(err, "pidgin") // "The escrow don freeze, dispute dey ground"
// Get all error messages for a language
getAllErrorMessages("pidgin") // { NotAuthorized: "Na only authorized pesin...", ... }Escrow Modes
| Mode | How it works | |---|---| | Simple | Both parties confirm and funds release instantly. Timelock protects if one goes silent. | | Milestone | SOL releases in chunks per approved milestone. 3 rejections triggers auto-dispute. | | MultiParty | Multiple signers. Majority or unanimous release depending on releaseCondition. | | Timed | Auto-releases at a unix timestamp. No confirmation needed. |
Timelocks
| Amount | Timelock | |---|---| | Less than 0.0067 SOL | 1 hour | | Less than 0.067 SOL | 6 hours | | Less than 0.67 SOL | 24 hours | | 0.67 SOL and above | 72 hours |
Speed settings (standard, express, instant) let both parties agree to shorten the timelock. One party alone cannot force it.
Program
| | |
|---|---|
| Program ID | GuDNhDbxfmpAt3zDg9TSPdzAYvARifeFTqUhQRtsmjuC |
| Network | Solana Devnet |
| Audit | Pending |
License
ISC
