diff --git a/README.md b/README.md index 93b458a..e60d323 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Trustless Work Development Skill -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented separately in [skills/api/v2/](skills/api/v2/); the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented separately in [skills/api/v2/](skills/api/v2/); the V2 React SDK is documented in [skills/react-sdk/v2/](skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](constitution.md). [View on skills.sh](https://www.skills.sh/trustless-work/trustlesswork-skill) diff --git a/SKILL.md b/SKILL.md index 2600d79..c95f53e 100644 --- a/SKILL.md +++ b/SKILL.md @@ -36,7 +36,7 @@ npx skills add trustless-work/trustlesswork-skill Trustless Work has two protocol versions, and they are not interchangeable. - **V1 is production and the default.** It is the only version deployed on mainnet. Build every normal integration from [skills/protocol/v1.md](skills/protocol/v1.md). -- **V2 is beta and testnet-only.** It is deployed on testnet, so you can build on it there — contract semantics in [skills/protocol/v2.md](skills/protocol/v2.md), REST endpoints in [skills/api/v2/](skills/api/v2/core-concepts.md) — but never on mainnet while it is beta, and never as the recommended production path. Say it is beta every time. +- **V2 is beta and testnet-only.** It is deployed on testnet, so you can build on it there — contract semantics in [skills/protocol/v2.md](skills/protocol/v2.md), REST endpoints in [skills/api/v2/](skills/api/v2/core-concepts.md), React SDK in [skills/react-sdk/v2/](skills/react-sdk/v2/react-sdk.md), JS SDK in [skills/js-sdk/](skills/js-sdk/js-sdk.md) — but never on mainnet while it is beta, and never as the recommended production path. Say it is beta every time. - **Explaining V2 is always in scope.** Answer any V2 question; the restriction is which network you target, not whether the user said "beta". - **Never mix them.** Roles, payload shapes, approval semantics and lifecycle rules belong to one version at a time. - **If the version is ambiguous, use V1** and state which version you are describing. @@ -101,6 +101,12 @@ Load these on demand — only when the task requires them: - Read **[skills/api/v2/single-release.md](skills/api/v2/single-release.md)** when implementing any single-release v2 endpoint. - Read **[skills/api/v2/multi-release.md](skills/api/v2/multi-release.md)** when implementing any multi-release v2 endpoint. +### React SDK — V2 (beta, testnet only) +- Read **[skills/react-sdk/v2/react-sdk.md](skills/react-sdk/v2/react-sdk.md)** when integrating `@trustless-work/escrow` 5.x: provider setup, the build/sign/submit loop, every hook, and the new GraphQL hooks. + +### JavaScript SDK — V2 (beta) +- Read **[skills/js-sdk/js-sdk.md](skills/js-sdk/js-sdk.md)** when the integration is **not** React — Node, NestJS, Angular, browser, scripts. `@trustless-work/escrow-js` is framework-agnostic, zero-dependency, and V2-only. + ### React SDK - Read **[skills/react-sdk/react-sdk.md](skills/react-sdk/react-sdk.md)** for SDK setup, provider config, and hook overview. - Read **[skills/react-sdk/hooks-reference.md](skills/react-sdk/hooks-reference.md)** for complete parameter docs and examples of any specific hook (`useInitializeEscrow`, `useFundEscrow`, `useApproveMilestone`, `useReleaseFunds`, `useStartDispute`, `useResolveDispute`, `useUpdateEscrow`, `useChangeMilestoneStatus`, `useWithdrawRemainingFunds`, `useSendTransaction`). diff --git a/skills/api/core-concepts.md b/skills/api/core-concepts.md index e05c4b8..c58ebf9 100644 --- a/skills/api/core-concepts.md +++ b/skills/api/core-concepts.md @@ -1,6 +1,6 @@ # Core Concepts -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented separately in [skills/api/v2/](v2/); the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented separately in [skills/api/v2/](v2/); the V2 React SDK is documented in [skills/react-sdk/v2/](../../skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). ## Overview diff --git a/skills/api/multi-release-escrow.md b/skills/api/multi-release-escrow.md index 92025a0..78fae83 100644 --- a/skills/api/multi-release-escrow.md +++ b/skills/api/multi-release-escrow.md @@ -1,6 +1,6 @@ # Multi-Release Escrow -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented separately in [skills/api/v2/](v2/); the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented separately in [skills/api/v2/](v2/); the V2 React SDK is documented in [skills/react-sdk/v2/](../../skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). Multi-release escrows release funds incrementally as each milestone is completed and approved. diff --git a/skills/api/single-release-escrow.md b/skills/api/single-release-escrow.md index bb78f35..19e2657 100644 --- a/skills/api/single-release-escrow.md +++ b/skills/api/single-release-escrow.md @@ -1,6 +1,6 @@ # Single-Release Escrow -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented separately in [skills/api/v2/](v2/); the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented separately in [skills/api/v2/](v2/); the V2 React SDK is documented in [skills/react-sdk/v2/](../../skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). Single-release escrows release all funds in one payment after all milestones are completed and approved. diff --git a/skills/api/types.md b/skills/api/types.md index f970b2e..f6435c6 100644 --- a/skills/api/types.md +++ b/skills/api/types.md @@ -1,6 +1,6 @@ # TypeScript Types Reference -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented separately in [skills/api/v2/](v2/); the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented separately in [skills/api/v2/](v2/); the V2 React SDK is documented in [skills/react-sdk/v2/](../../skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). Complete TypeScript type definitions for all Trustless Work API payloads, responses, and errors. diff --git a/skills/blocks/components.md b/skills/blocks/components.md index f827777..009192b 100644 --- a/skills/blocks/components.md +++ b/skills/blocks/components.md @@ -1,6 +1,6 @@ # Blocks Components -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK is documented in [skills/react-sdk/v2/](../../skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). Pre-built UI components for escrow management interfaces. All components can be installed via CLI and are fully customizable. diff --git a/skills/blocks/hooks.md b/skills/blocks/hooks.md index 07a47dd..4dd5daa 100644 --- a/skills/blocks/hooks.md +++ b/skills/blocks/hooks.md @@ -1,6 +1,6 @@ # Blocks TanStack Query Hooks -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK is documented in [skills/react-sdk/v2/](../../skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). TanStack Query hooks for fetching and mutating escrows. diff --git a/skills/blocks/introduction.md b/skills/blocks/introduction.md index e0d6bc9..ac8a16e 100644 --- a/skills/blocks/introduction.md +++ b/skills/blocks/introduction.md @@ -1,6 +1,6 @@ # Blocks SDK Introduction -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK is documented in [skills/react-sdk/v2/](../../skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). The Trustless Work Blocks SDK (`@trustless-work/blocks`) provides pre-built UI components, providers, and TanStack Query hooks for quickly building escrow management interfaces. diff --git a/skills/blocks/providers.md b/skills/blocks/providers.md index 7872c51..e35600b 100644 --- a/skills/blocks/providers.md +++ b/skills/blocks/providers.md @@ -1,6 +1,6 @@ # Blocks Providers -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK is documented in [skills/react-sdk/v2/](../../skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). Providers for escrow state, wallet context, dialogs, and amount formatting. **Provider order is critical** — do not reorder. diff --git a/skills/blocks/vibe-coding.md b/skills/blocks/vibe-coding.md index 604a25d..b07cc71 100644 --- a/skills/blocks/vibe-coding.md +++ b/skills/blocks/vibe-coding.md @@ -1,6 +1,6 @@ # Vibe Coding Guide -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK is documented in [skills/react-sdk/v2/](../../skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). Single-file AI context guide for Trustless Work Escrow Blocks with Next.js. Built for agent workflows. diff --git a/skills/js-sdk/js-sdk.md b/skills/js-sdk/js-sdk.md new file mode 100644 index 0000000..df1a280 --- /dev/null +++ b/skills/js-sdk/js-sdk.md @@ -0,0 +1,176 @@ +# JavaScript SDK v2 — `@trustless-work/escrow-js` + +> **Protocol version: V2 (BETA).** Framework-agnostic client over Core API v2, served from `https://beta.api.trustlesswork.com`. There is no V1 equivalent of this package. For React use [@trustless-work/escrow 5.x](../react-sdk/v2/react-sdk.md); for the REST endpoints and payload shapes see [skills/api/v2/](../api/v2/core-concepts.md). + +Use this SDK outside React: Node services, NestJS, Angular, plain browser, scripts, tests, edge runtimes. + +--- + +## Install + +```bash +npm i @trustless-work/escrow-js@beta +``` + +Install under the **`beta`** dist-tag while Core v2 is in beta. + +Requires **Node 18+** for global `fetch`. **Zero runtime dependencies** — no Axios, no React. + +## Create a client + +```ts +import { TrustlessWorkClient, development } from "@trustless-work/escrow-js"; + +const client = new TrustlessWorkClient({ + baseURL: development, + apiKey: process.env.API_KEY, +}); + +await client.rest.listEscrows({ scope: "mine", limit: 20 }); +await client.graphql.getEscrow({ contractId: "C..." }); +``` + +This instance pattern is the one to use with dependency injection — NestJS providers, Angular services — and anywhere you need more than one configuration. + +There is also a module-level default: `configureTrustlessWork(...)` once at startup, then `getTrustlessWorkClient()`, `escrowRest()` and `escrowGraphql()` anywhere. Prefer the explicit instance in server code; the default is convenient for scripts. + +### Options + +| Option | Type | Purpose | +| --- | --- | --- | +| `baseURL` | `string` | API host. | +| `apiKey` | `string` | Sent as `x-api-key`. Required for writes. | +| `getAccessToken` | `() => string \| Promise` | Wallet-session auth. **May be async here**, unlike the React SDK. | +| `defaultHeaders` | `Record` | Extra headers on every request. | + +> **`mainNet` and `development` both resolve to the beta host.** The package exports both names, but while V2 is beta they point at the same URL. `mainNet` does not mean production — V2 is not deployed to mainnet. + +--- + +## The signing loop + +Identical to the React SDK, minus the hooks. + +```ts +// 1. Build +const { unsignedXdr } = await client.rest.fundEscrow( + { contractId, signer, amount: 1000 }, + "single-release", +); + +// 2. Sign with the wallet the operation requires (your wallet layer) +const signedXdr = await signWithWallet(unsignedXdr); + +// 3. Submit +const result = await client.rest.sendTransaction(signedXdr); +``` + +The build response is `{ unsignedXdr, txHash }`. **`deployEscrow` adds the predicted `contractId`**, so you know the escrow's identity before submitting: + +```ts +const { unsignedXdr, txHash, contractId } = await client.rest.deployEscrow( + payload, + "single-release", +); +``` + +### Reading the submit result + +```ts +type SendTransactionResponse = { + txHash: string; + ledger: number; + contractId?: string; // present on deploy confirmation + escrow?: Escrow; // present on deploy confirmation + code?: SendTransactionCode; + message?: string; +}; +``` + +| `code` | Meaning | +| --- | --- | +| `STELLAR_TX_SUBMITTED` | Submitted and indexed. | +| `STELLAR_TX_SUBMITTED_INDEXER_LAGGING` | **The transaction succeeded.** Only the read model is behind. Do not retry — re-read after a moment. | + +Treating the lagging code as a failure and resubmitting is the most expensive mistake available here. + +--- + +## Methods + +Same surface as the React SDK, reached through `client.rest` and `client.graphql` instead of hooks. + +### Operate — build transactions + +`deployEscrow(payload, type, attribution?)` · `fundEscrow(payload, type)` · `updateEscrow(payload, type)` · `manageMilestones(payload, type)` · `changeMilestoneStatus(payload, type)` · `approveMilestones(payload, type)` · `approveAndReleaseMilestones(payload)` · `releaseFunds(payload, type)` · `releaseMilestones(payload)` · `startDispute(payload, type)` · `disputeMilestones(payload)` · `resolveDispute(payload, type)` · `withdrawRemainingFunds(payload, type)` + +`releaseMilestones`, `disputeMilestones` and `approveAndReleaseMilestones` are multi-release only and take no `type`. For the first two the operation does not exist on single-release; approve-and-release **does** exist there in the API (`POST /escrow/single-release/v2/approve-and-release-milestones`) — the SDK just does not wrap it, so call that route directly. + +`extend-ttl` is not wrapped either — call `POST /escrow/{type}/v2/extend-ttl` directly. + +### Submit + +`sendTransaction(signedXdr)` + +### REST reads + +`listEscrows(params?)` · `getEscrow(contractId)` · `getEscrowDetails(contractIds)` · `listEscrowEvents(contractId, params?)` · `getEscrowMilestones(contractId)` · `getEscrowsMilestones(contractIds)` · `getEscrowsFinancial(contractIds)` + +Batch methods accept a `string[]` of contract IDs. Use them rather than looping single reads. + +> These hit the **read model** at `/escrows/...`, which is neither version-scoped nor type-scoped — there is no `/v2/` in those paths. The v2 transaction controllers expose their own `GET /escrow/{type}/v2/:contractId`, but the SDK does not use it. Read amounts come back as **decimal strings**. + +### GraphQL reads + +`client.graphql.getEscrow(variables)` · `client.graphql.listEscrows(variables)` + +`listEscrows` filters on `scope` (`"mine"` | `"all"`), `status`, `contractType`, `engagementId`, `contractIds`, `participant`, `role`, `platformId`, `subjectId`, `createdAfter`/`createdBefore`. Paginate with `limit` + `cursor` (keyset, not offsets); sort by `createdAt` or `updatedAt`. + +--- + +## Errors + +| Class | When | +| --- | --- | +| `TrustlessWorkApiError` | The API answered with a Problem Details body. Carries the status and machine-readable detail. | +| `TrustlessWorkNetworkError` | The request never got a usable response — DNS, timeout, offline. | + +Use `parseProblemDetailsFromResponse` when handling a raw `Response` yourself. The React SDK's Axios-specific `parseProblemDetailsFromAxiosError` does not exist here. + +--- + +## Coming from the React SDK + +Payloads, responses, error codes and the Core v2 contract are **identical**. Only the React layer is removed. + +| React SDK | JS SDK | +| --- | --- | +| `TrustlessWorkConfig` | `new TrustlessWorkClient(...)` or `configureTrustlessWork(...)` | +| `useTrustlessWorkClient()` | your client instance, or `getTrustlessWorkClient()` | +| `useEscrowRest()` | `client.rest` or `escrowRest()` | +| `useEscrowGraphql()` | `client.graphql` or `escrowGraphql()` | +| `useDeployEscrow().deployEscrow` | `client.rest.deployEscrow` | +| `useSendTransaction().sendTransaction` | `client.rest.sendTransaction` | +| `useGraphqlListEscrows().listEscrows` | `client.graphql.listEscrows` | + +Every other hook follows the same rule: drop `use`, call the method on `client.rest`. + +### Transport differences + +| | React SDK | JS SDK | +| --- | --- | --- | +| HTTP | Axios | Native `fetch` | +| Runtime deps | `axios` + React peers | none | +| Token getter | sync only | sync **or** async | +| Non-Problem errors | raw Axios error | `TrustlessWorkNetworkError` | + +--- + +## Common mistakes + +* **Destructuring `unsignedTransaction`.** The field is `unsignedXdr`. +* **Retrying on `STELLAR_TX_SUBMITTED_INDEXER_LAGGING`.** The transaction already landed. +* **Assuming `mainNet` is production.** Both host constants point at the beta host today. +* **Expecting read amounts to be numbers.** Operate payloads take numbers; read responses return decimal strings. +* **Installing `latest`.** Use the `@beta` dist-tag while Core v2 is beta. +* **Running on Node < 18.** There is no `fetch` polyfill in the package. diff --git a/skills/react-sdk/hooks-reference.md b/skills/react-sdk/hooks-reference.md index f07534c..734a4b8 100644 --- a/skills/react-sdk/hooks-reference.md +++ b/skills/react-sdk/hooks-reference.md @@ -1,6 +1,6 @@ # React SDK Hooks Reference -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK is documented in [skills/react-sdk/v2/](../../skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). Complete reference for all Trustless Work React SDK hooks with detailed usage examples. diff --git a/skills/react-sdk/react-sdk.md b/skills/react-sdk/react-sdk.md index e52cb5e..f8737e1 100644 --- a/skills/react-sdk/react-sdk.md +++ b/skills/react-sdk/react-sdk.md @@ -1,6 +1,6 @@ # React SDK -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK is documented in [skills/react-sdk/v2/](../../skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). The Trustless Work React SDK (`@trustless-work/escrow`) provides custom hooks for integrating escrow functionality into React/Next.js applications. It uses Axios for HTTP requests. diff --git a/skills/react-sdk/v2/react-sdk.md b/skills/react-sdk/v2/react-sdk.md new file mode 100644 index 0000000..832ab4e --- /dev/null +++ b/skills/react-sdk/v2/react-sdk.md @@ -0,0 +1,198 @@ +# React SDK v2 — `@trustless-work/escrow` 5.x + +> **Protocol version: V2 (BETA), testnet only.** SDK 5.x targets the **v2** Core API exclusively — every transaction hook builds `/escrow/{type}/v2/...` routes. For V1 integrations use SDK 3.x and the [V1 React SDK reference](../react-sdk.md). + +The REST endpoints and payload shapes this SDK wraps are documented in [skills/api/v2/core-concepts.md](../../api/v2/core-concepts.md). This file covers the React surface: setup, hooks, and the signing loop. + +--- + +## Install + +```bash +npm install @trustless-work/escrow@5 +``` + +Peer requirement: a wallet integration that can sign a Stellar XDR — commonly `@creit.tech/stellar-wallets-kit`. + +## Provider setup + +Wrap your app once. The provider is a client component, so in Next.js App Router it needs `"use client"` in the file that renders it. + +```tsx +"use client"; + +import { TrustlessWorkConfig } from "@trustless-work/escrow"; + +export function Providers({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} +``` + +### Configuration options + +| Prop | Type | Purpose | +| --- | --- | --- | +| `baseURL` | `string` | API host. V2 lives on `https://beta.api.trustlesswork.com`, not on the V1 hosts. | +| `apiKey` | `string` | Sent as `x-api-key`. | +| `getAccessToken` | `() => string \| undefined \| null` | Alternative to a static key — called per request, for session-based auth. | +| `defaultHeaders` | `Record` | Extra headers on every request. | + +`apiKey` and `getAccessToken` can coexist; the getter is re-read on each call, so it suits rotating tokens. + +> The package also exports `mainNet` and `development` host constants. Do **not** read them as environments: both point at the beta backend — through its internal hosting URL, not the branded host — and `mainNet` is not production (V2 is not on mainnet). Pass the explicit `baseURL` shown above instead. + +> SDK 5.x does **not** require a `QueryClientProvider`. It has no TanStack Query dependency — hooks return plain async functions, so you own the caching strategy. + +--- + +## The signing loop + +Every transaction hook **builds** a transaction. It never submits one. The shape is always the same: + +```tsx +"use client"; + +import { useFundEscrow, useSendTransaction } from "@trustless-work/escrow"; +import { signTransaction } from "@/lib/wallet"; + +export function FundButton({ contractId, signer }: Props) { + const { fundEscrow } = useFundEscrow(); + const { sendTransaction } = useSendTransaction(); + + async function onFund() { + // 1. Build — the field is `unsignedXdr`, not `unsignedTransaction` + const { unsignedXdr } = await fundEscrow( + { contractId, signer, amount: 1000 }, + "single-release", + ); + + // 2. Sign with the wallet the operation requires + const signedXdr = await signTransaction(unsignedXdr); + + // 3. Submit + const result = await sendTransaction(signedXdr); + // result.code === "STELLAR_TX_SUBMITTED_INDEXER_LAGGING" means it worked + // but the read model is behind — do not retry the transaction. + } + + return ; +} +``` + +Skipping step 3 means nothing reaches the chain. This is the single most common integration mistake. + +### The `type` argument + +Most transaction hooks take the escrow type as a second argument: + +```ts +type EscrowType = "single-release" | "multi-release"; +``` + +It must match the payload type you pass. A multi-release payload with `"single-release"` hits the wrong route and fails. + +A few methods are multi-release only and take no type: `releaseMilestones`, `disputeMilestones` and `approveAndReleaseMilestones`. For the first two the operation does not exist on single-release. Approve-and-release is different: the API **does** expose `POST /escrow/single-release/v2/approve-and-release-milestones` — the SDK just does not wrap it, so for single-release call that route directly. + +--- + +## Transaction hooks + +| Hook | Method | Signed by | Notes | +| --- | --- | --- | --- | +| `useDeployEscrow` | `deployEscrow(payload, type, attribution?)` | `signer` | Accepts optional attribution headers | +| `useFundEscrow` | `fundEscrow(payload, type)` | any depositor | | +| `useUpdateEscrow` | `updateEscrow(payload, type)` | `admin` | Only before the first fund (lock is cumulative `FundedAmount`, never resets) | +| `useManageMilestones` | `manageMilestones(payload, type)` | `admin` | Add or edit milestones | +| `useChangeMilestoneStatus` | `changeMilestoneStatus(payload, type)` | a service provider | Batched `updates` | +| `useApproveMilestones` | `approveMilestones(payload, type)` | an approver | One vote per listed milestone | +| `useApproveAndReleaseMilestones` | `approveAndReleaseMilestones(payload)` | approver + release signer | **Multi-release only** in the SDK (see above) | +| `useReleaseFunds` | `releaseFunds(payload, type)` · `releaseMilestones(payload)` | a release signer | The second is multi-release only | +| `useStartDispute` | `startDispute(payload, type)` · `disputeMilestones(payload)` | see below | `disputeMilestones` is multi-release only | +| `useResolveDispute` | `resolveDispute(payload, type)` | a dispute resolver | | +| `useWithdrawRemainingFunds` | `withdrawRemainingFunds(payload, type)` | a dispute resolver | Terminal escrows only | +| `useSendTransaction` | `sendTransaction(signedXdr)` | — | `POST /stellar/send-transaction` | + +> **The submit route changed.** V1 documents `POST /helper/send-transaction`. SDK 5.x posts to `/stellar/send-transaction`. Use `useSendTransaction` and you never have to hardcode it. + +Dispute permissions follow the contract: approvers, service providers, release signers, the platform and the receiver may open one. A dispute resolver may not — the contract rejects it. + +`extend-ttl` has **no hook** — neither SDK wraps it. When you need it, call `POST /escrow/{type}/v2/extend-ttl` directly. + +## Read hooks + +These query the indexer read model, not the chain directly. + +> These hit the **read model** at `/escrows/...`, which is neither version-scoped nor type-scoped — there is no `/v2/` in those paths. The v2 transaction controllers expose their own `GET /escrow/{type}/v2/:contractId`, but the SDK does not use it. Read amounts come back as **decimal strings**. + +| Hook | Method | Returns | +| --- | --- | --- | +| `useGetEscrow` | `getEscrow(contractId)` | One escrow | +| `useListEscrows` | `listEscrows(params?)` | Keyset-paginated list | +| `useGetEscrowDetails` | `getEscrowDetails(contractIds)` | Batch detail lookup | +| `useGetEscrowMilestones` | `getEscrowMilestones(contractId)` | Milestones for one escrow | +| `useGetEscrowsMilestones` | `getEscrowsMilestones(contractIds)` | Milestones for many | +| `useGetEscrowsFinancial` | `getEscrowsFinancial(contractIds)` | Financial summary for many | +| `useListEscrowEvents` | `listEscrowEvents(contractId, params?)` | Event history | + +Batch hooks accept either a `string[]` of contract IDs or a params object — use the batch form rather than looping single reads. + +## GraphQL hooks + +New in 5.x. Same read model, one round trip, and you choose the fields. + +| Hook | Method | REST twin | +| --- | --- | --- | +| `useGraphqlGetEscrow` | `getEscrow(variables)` | `GET /escrows/:id` | +| `useGraphqlListEscrows` | `listEscrows(variables?)` | `GET /escrows` | + +```tsx +const { listEscrows } = useGraphqlListEscrows(); +const page = await listEscrows({ scope: "mine", limit: 20, sort: "createdAt", order: "desc" }); +``` + +`listEscrows` filters on `scope` (`"mine"` or `"all"`), `status`, `contractType`, `engagementId`, `contractIds`, `participant`, `role`, `platformId`, `subjectId` and a `createdAfter`/`createdBefore` range. Paginate with `limit` plus `cursor` — it is keyset pagination, not offsets. Sort by `createdAt` or `updatedAt`. + +The exported documents `GRAPHQL_GET_ESCROW` and `GRAPHQL_LIST_ESCROWS` are available if you prefer your own client. Errors surface as `GraphqlRequestError`. + +Prefer GraphQL when a screen needs several related pieces of one escrow; prefer the REST batch reads when you need the same shape across many escrows. + +## Attribution headers + +`deployEscrow` accepts an optional third argument that tags the escrow with the platform and end user that created it: + +```ts +await deployEscrow(payload, "single-release", { + platformId: "my-platform", // X-TW-Platform + subjectId: "user-123", // X-TW-Subject +}); +``` + +Useful when one API key serves several platforms or tenants. + +--- + +## Direct service access + +The hooks are thin wrappers. Outside React — a server action, a script, a test — use the services directly: + +```ts +import { TrustlessWorkClient, EscrowRestService } from "@trustless-work/escrow"; +``` + +`useTrustlessWorkClient`, `useEscrowRest` and `useEscrowGraphql` expose the same objects inside React. + +## Common mistakes + +* **Forgetting `sendTransaction`.** The hook returns `unsignedXdr`; nothing happens until you sign and submit. +* **Mismatching `type` and payload.** `"single-release"` needs a `SingleRelease*Payload`. +* **Signing with the wrong wallet.** Each operation names its required signer; the contract rejects anything else. +* **Reusing V1 payload shapes.** Roles are arrays in v2, `milestoneIndexes` is `number[]`, and milestone approval is a threshold. See [skills/api/v2/core-concepts.md](../../api/v2/core-concepts.md). +* **Pointing `baseURL` at a V1 host.** V2 is served only from `https://beta.api.trustlesswork.com`; neither `api.trustlesswork.com` nor `dev.api.trustlesswork.com` serves it. +* **Expecting a `QueryClientProvider` requirement.** 5.x does not use TanStack Query; that was the 3.x pattern. diff --git a/skills/react-sdk/vibe-coding.md b/skills/react-sdk/vibe-coding.md index 74226da..c797119 100644 --- a/skills/react-sdk/vibe-coding.md +++ b/skills/react-sdk/vibe-coding.md @@ -1,6 +1,6 @@ # Vibe Coding Guide -> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK and Blocks surfaces are **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). +> **Protocol version: V1.** This file documents the production V1 integration — the only version deployed on mainnet. The V2 Core API is documented in [skills/api/v2/](../api/v2/), but the V2 React SDK is documented in [skills/react-sdk/v2/](../../skills/react-sdk/v2/react-sdk.md); the V2 Blocks surface is **not** documented yet. For the contract-level differences see [constitution.md](../../constitution.md). In all of your chat prompts, you should provide the agent with specific document references, including the global content rules and the complete code project. ***GPT 5 gives the best result***