
Product
Socket Now Protects the Firefox Extension Ecosystem
Socket is bringing experimental protection to Firefox, scanning 97,000+ extensions in Mozilla's official directory for malware and risky updates.
@trustless-work/escrow
Advanced tools
@trustless-work/escrow v5 — React/TypeScript client for Trustless Work Core API v2 escrows.
| Surface | What it does |
|---|---|
| REST operate | Build unsigned XDR → you sign → sendTransaction |
| REST reads | GET /escrows* (list, detail, events, milestones, financial) |
| GraphQL reads | POST /graphql (escrow / escrows) |
Identity is always contractId (Soroban C…). Types: single-release | multi-release.
Auth, users, platforms, wallets, admin, and access grants are out of scope for this package.
npm install @trustless-work/escrow@5
# or
yarn add @trustless-work/escrow@5
# or
pnpm add @trustless-work/escrow@5
Peer dependencies: react and react-dom >=18 <20.
If you publish/install under an npm dist-tag (e.g. beta), use that tag instead of @5 so latest can stay on the audited Core v1 line.
"use client";
import {
development,
TrustlessWorkConfig,
} from "@trustless-work/escrow";
export function TrustlessWorkProvider({
children,
}: {
children: React.ReactNode;
}) {
const apiKey = process.env.NEXT_PUBLIC_API_KEY || "";
return (
<TrustlessWorkConfig baseURL={development} apiKey={apiKey}>
{children}
</TrustlessWorkConfig>
);
}
Optional wallet-session auth and default platform header:
<TrustlessWorkConfig
baseURL={development}
apiKey={apiKey}
getAccessToken={() => sessionToken}
defaultHeaders={{ "X-TW-Platform": platformId }}
>
{children}
</TrustlessWorkConfig>
| Prop | Role |
|---|---|
baseURL | Core API host (development / mainNet helpers, or any URL string) |
apiKey | x-api-key header |
getAccessToken | Optional Bearer token getter (re-read per request) |
defaultHeaders | Merged into every request (e.g. X-TW-Platform) |
import { TrustlessWorkClient, development } from "@trustless-work/escrow";
const client = new TrustlessWorkClient({
baseURL: development,
apiKey: process.env.API_KEY,
});
await client.rest.listEscrows({ scope: "mine", limit: 20 });
await client.graphql.getEscrow({ contractId });
| Import | Contains |
|---|---|
@trustless-work/escrow | Config, client, REST + GraphQL hooks, types, errors |
@trustless-work/escrow/rest | EscrowRestService + REST hooks only |
@trustless-work/escrow/graphql | GraphQL service, documents, GraphQL hooks |
@trustless-work/escrow/hooks | All hooks (REST + GraphQL) |
@trustless-work/escrow/hooks/rest | REST hooks only |
@trustless-work/escrow/hooks/graphql | GraphQL hooks only |
@trustless-work/escrow/types | Payloads, responses, read-model, entities |
import { useEscrowRest, useEscrowGraphql } from "@trustless-work/escrow";
import { useGraphqlGetEscrow } from "@trustless-work/escrow/hooks/graphql";
const rest = useEscrowRest(); // operate + GET /escrows*
const graphql = useEscrowGraphql(); // POST /graphql
const { getEscrow } = useGraphqlGetEscrow();
Every mutate hook returns an unsigned transaction. You sign with the wallet, then submit.
import {
useDeployEscrow,
useSendTransaction,
toTrustlessWorkError,
TrustlessWorkApiError,
formatApiErrorMessage,
} from "@trustless-work/escrow";
import type { DeploySingleReleaseEscrowPayload } from "@trustless-work/escrow/types";
const { deployEscrow } = useDeployEscrow();
const { sendTransaction } = useSendTransaction();
const onSubmit = async (payload: DeploySingleReleaseEscrowPayload) => {
try {
const { unsignedXdr, contractId } = await deployEscrow(
payload,
"single-release",
// optional attribution → X-TW-Platform / X-TW-Subject:
// { platformId, subjectId }
);
const signedXdr = await signWithWallet(unsignedXdr);
const result = await sendTransaction(signedXdr);
// result.txHash, result.ledger, result.contractId?, result.escrow?, result.code?
if (result.code === "STELLAR_TX_SUBMITTED_INDEXER_LAGGING") {
// Tx is on-chain; poll GET /escrows/:contractId until the indexer catches up
}
} catch (error: unknown) {
const normalized = toTrustlessWorkError(error);
if (normalized instanceof TrustlessWorkApiError) {
console.error(formatApiErrorMessage(normalized), normalized.code);
}
throw error;
}
};
Deploy trustline shape: { contractId, symbol } (Soroban SAC C… + asset code).
Operate responses:
| Step | Type | Shape |
|---|---|---|
| Deploy build | DeployEscrowResponse | { unsignedXdr, txHash, contractId } |
| Other builds | BuildTransactionResponse | { unsignedXdr, txHash } |
| Submit | SendTransactionResponse | { txHash, ledger, contractId?, escrow?, code?, message? } |
code may be STELLAR_TX_SUBMITTED or STELLAR_TX_SUBMITTED_INDEXER_LAGGING.
Import from @trustless-work/escrow, @trustless-work/escrow/hooks, or @trustless-work/escrow/hooks/rest.
| Hook | Action |
|---|---|
useDeployEscrow | Create escrow (unsignedXdr + predicted contractId) |
useFundEscrow | Fund |
useUpdateEscrow | Update properties |
useChangeMilestoneStatus | Status / evidence (batch) |
useApproveMilestones | Approve (batch) |
useApproveAndReleaseMilestones | Approve + release (multi-release) |
useManageMilestones | Add / edit milestones |
useReleaseFunds | Release |
useStartDispute | Start dispute |
useResolveDispute | Resolve dispute (distributions) |
useWithdrawRemainingFunds | Withdraw remaining |
useSendTransaction | Submit signed XDR (POST /stellar/send-transaction) |
Most operate methods take (payload, type) where type is "single-release" | "multi-release". Multi-only helpers (approveAndReleaseMilestones, etc.) omit the type argument.
| Hook | Endpoint |
|---|---|
useListEscrows | GET /escrows |
useGetEscrow | GET /escrows/:contractId |
useGetEscrowDetails | GET /escrows/details?contractIds= |
useListEscrowEvents | GET /escrows/:contractId/events |
useGetEscrowMilestones | GET /escrows/:contractId/milestones |
useGetEscrowsMilestones | GET /escrows/milestones?contractIds= |
useGetEscrowsFinancial | GET /escrows/financial?contractIds= |
import { useListEscrows, useGetEscrow } from "@trustless-work/escrow/hooks/rest";
import { useQuery } from "@tanstack/react-query";
const { listEscrows } = useListEscrows();
const { getEscrow } = useGetEscrow();
useQuery({
queryKey: ["escrows", "mine"],
queryFn: () => listEscrows({ scope: "mine", limit: 20 }),
});
useQuery({
queryKey: ["escrow", contractId],
queryFn: () => getEscrow(contractId),
enabled: !!contractId,
});
ListEscrowsParams (filters)scope, status, contractType, engagementId, contractIds, participant, role, platformId, subjectId, createdAfter, createdBefore, limit, cursor, sort, order.
scope: "mine" | "all" for segmentation (not per-escrow access grants).{ data, hasMore, nextCursor }.| Type | Notes |
|---|---|
EscrowSummary | List/detail row: contractId, type, status, balance, asset, camelCased snapshot |
EscrowDetail | { escrow, events, deposits } |
EscrowFinancial | Batch financial: deposited / released / pending / balance |
EscrowEvent | Indexed event (kind, topics, payload, …) — no UUID event id |
EscrowDeposit | Deposit row — no UUID deposit id |
There is no UUID id / escrowId. Amounts on reads are human decimal strings (e.g. "250.5") — do not divide by 1e7. Build/operate payloads still use human numbers.
| Hook | Query |
|---|---|
useGraphqlGetEscrow | escrow(contractId) + financial / deposits / events |
useGraphqlListEscrows | escrows(...) (same filters as REST list) |
Documents: GRAPHQL_GET_ESCROW, GRAPHQL_LIST_ESCROWS.
import { useGraphqlGetEscrow, useGraphqlListEscrows } from "@trustless-work/escrow/hooks/graphql";
const { getEscrow } = useGraphqlGetEscrow();
const { listEscrows } = useGraphqlListEscrows();
const detail = await getEscrow({
contractId,
eventsLimit: 20,
});
const page = await listEscrows({
scope: "mine",
limit: 20,
});
GraphQL wire types (GraphqlEscrow, GraphqlEscrowPage, …) live on @trustless-work/escrow / @trustless-work/escrow/graphql.
HTTP failures from Core are RFC 9457 Problem Details. The transport surfaces them as TrustlessWorkApiError.
import {
toTrustlessWorkError,
TrustlessWorkApiError,
formatApiErrorMessage,
ESCROW_ERROR_CODES,
} from "@trustless-work/escrow";
try {
await fundEscrow(payload, "single-release");
} catch (error: unknown) {
const err = toTrustlessWorkError(error);
if (err instanceof TrustlessWorkApiError) {
// err.code, err.status, err.detail, err.traceId, err.extensions
toast.error(formatApiErrorMessage(err));
if (err.code === ESCROW_ERROR_CODES.ESCROW_NOT_FOUND) { /* … */ }
}
}
Also exported: parseProblemDetails, parseProblemDetailsFromAxiosError, isProblemDetails, isEscrowErrorCode.
Import from @trustless-work/escrow/types (or the root package):
| Area | Examples |
|---|---|
| Operate payloads | DeploySingleReleaseEscrowPayload, FundEscrowPayload, ApproveMilestonesPayload, AttributionHeaders, … |
| Responses | DeployEscrowResponse, BuildTransactionResponse, SendTransactionResponse, ListEscrowsResponse, … |
| Reads | EscrowSummary, EscrowAsset, EscrowSnapshot, EscrowEvent, EscrowFinancial, KeysetPage, … |
| Entities | Escrow, Roles, DeployTrustline, SingleReleaseMilestone, … |
| Errors | ApiProblemDetails, EscrowErrorCode, ESCROW_ERROR_CODES |
development and mainNet currently point at:
https://trustless-core-production.up.railway.app
Pass any Core API baseURL string when you need another host. Get an API key from the Trustless Work dApp.
Breaking changes aligned with the Core v2 wire contract:
/helper/get-escrows-by-*, /helper/get-escrow-by-contract-ids, /helper/get-multiple-escrow-balance and their hooks.useListEscrows / useGetEscrow / useGetEscrowDetails / financial & milestones hooks (or GraphQL equivalents).contractId only (no UUID).contractId: { unsignedXdr, txHash, contractId }.{ contractId, symbol } (Soroban SAC + asset code).useDeployEscrow + Deploy*EscrowPayload (no Initialize* aliases).useApproveMilestones, useChangeMilestoneStatus, useManageMilestones, …).@trustless-work/escrow/rest and @trustless-work/escrow/graphql instead of mixing surfaces.EscrowSummary includes root balance (string) and asset { name, address, contractId }.balance, totalAmount, financial fields, snapshot amounts) are decimal strings.createdByUserId / creatorAddress are not on reads (on-chain state is public).scope=mine|all — not per-escrow access grants.STELLAR_TX_SUBMITTED_INDEXER_LAGGING and poll reads; balance is eventually consistent.MIT License — see LICENSE file for details.
FAQs
Unknown package
The npm package @trustless-work/escrow receives a total of 160 weekly downloads. As such, @trustless-work/escrow popularity was classified as not popular.
We found that @trustless-work/escrow demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket is bringing experimental protection to Firefox, scanning 97,000+ extensions in Mozilla's official directory for malware and risky updates.

Research
/Security News
Three compromised Rust crates pulled in a malicious dependency that downloaded and executed cross-platform malware during Cargo builds.

Research
/Security News
Socket uncovered 77 linked Firefox extensions, including 40 that steal wallet secrets or credentials and 37 deceptive sports-score shells.