Getting Started
Required Blocks
Support
Trustless Work React Library#
A production-ready set of React blocks for integrating Trustless Work's escrow and dispute resolution flows.
Would you like to customize the blocks?
You can do that by editing the blocks as you see fit.
What you get#
- UI blocks (cards/tables/dialogs/forms) to list and manage escrows
- Providers for API config, wallet context, dialogs and amounts
- TanStack Query hooks for fetching and mutating escrows
- Wallet-kit helpers and error handling utilities
List all available blocks#
With the CLI you can list all available blocks:
1npx trustless-work list
- Show all available blocks.
Context API#
The context API is a global storage of escrows. It is used to store the escrows that are fetched from the API. It is also used to store the selected escrow.
If you don't want to use our approach for retrieving the escrow data, you are completely free to change it. You can use Redux, Zustand, or any other solution instead. However, it is important that you ensure the desired escrow is passed to the endpoint.
Understanding how the context works in escrows endpoints.#
When implementing the endpoints, we need to pass the data of a specific escrow to each endpoint. But how do we do that? Our library provides a context called EscrowContext
, which includes some very important utilities. Among them areselectedEscrow
and setSelectedEscrow
, which allow us to do the following:
Use of selectedEscrow#
Currently, selectedEscrow
holds a specific escrow that we are pointing to. With this, all the endpoint hooks interact with that state in order to extract data from it, such as contractId, roles, etc. For example, in the change status select, the milestoneIndex
values are loaded based on the currently selected escrow. Therefore, ifsetSelectedEscrow
is undefined, they won't load.
1const { selectedEscrow } = useEscrowContext();
2
3const handleSubmit = form.handleSubmit(async (payload) => {
4 /**
5 * Create the final payload for the change milestone status mutation
6 *
7 * @param payload - The payload from the form
8 * @returns The final payload for the change milestone status mutation
9 */
10 const finalPayload: ChangeMilestoneStatusPayload = {
11 contractId: selectedEscrow?.contractId || '', // contractId from the selectedEscrow
12 milestoneIndex: payload.milestoneIndex,
13 newStatus: payload.status,
14 newEvidence: payload.evidence || undefined,
15 serviceProvider: walletAddress || '',
16 };
17
18 /**
19 * Call the change milestone status mutation
20 *
21 * @param payload - The final payload for the change milestone statusmutation
22 * @param type - The type of the escrow
23 * @param address - The address of the escrow
24 */
25 await changeMilestoneStatus.mutateAsync({
26 payload: finalPayload,
27 type: selectedEscrow?.type || 'multi-release',
28 address: walletAddress || '',
29 });
30}
Use of setSelectedEscrow#
The function setSelectedEscrow
save the selected escrow in the context, so that all the endpoint hooks interact with that state in order to extract data from it, such as contractId, roles, etc. For example, in escrows cards by signer we save the selected escrow in the context, so that we can use it in details dialog.
1const { setSelectedEscrow } = useEscrowContext();
2
3const onCardClick = (escrow: Escrow) => {
4 setSelectedEscrow(escrow);
5 dialogStates.second.setIsOpen(true);
6};
Use of updateEscrow#
Our updateEscrow
function update the existing selectedEscrow in the context. It is useful to update a flag or others fields. For example, we use it to update the escrow status after a change milestone status mutation.
1const { selectedEscrow, updateEscrow } = useEscrowContext();
2
3const handleSubmit = form.handleSubmit(async (payload) => {
4 /**
5 * Call the change milestone status mutation
6 *
7 * @param payload - The final payload for the change milestone status mutation
8 * @param type - The type of the escrow
9 * @param address - The address of the escrow
10 */
11 await changeMilestoneStatus.mutateAsync({
12 payload: finalPayload,
13 type: selectedEscrow?.type || "multi-release", // type from the selectedEscrow
14 address: walletAddress || "",
15 });
16
17 toast.success("Milestone status updated successfully");
18
19 // Update the selected escrow in the context with the new status and evidence
20 updateEscrow({
21 ...selectedEscrow,
22 milestones: selectedEscrow?.milestones.map((milestone, index) => {
23 if (index === Number(payload.milestoneIndex)) {
24 return {
25 ...milestone,
26 status: payload.status,
27 evidence: payload.evidence || undefined,
28 };
29 }
30 return milestone;
31 }),
32 });
33}
Installation based on folder path#
If you need all the child blocks, you can install them by pointing to their parent directory, so you won't have to install them one by one.
1npx trustless-work escrows // or other parent's blocks directory
Understanding the Block Structure#
When you specify a parent folder like escrows
, the CLI will install all blocks within that directory tree. Here's how the blocks are organized:
Trustless Work Blocks Structure
Install Parent Directory
1npx trustless-work add escrows
Installs ALL escrow blocks
Install Specific Subfolder
1npx trustless-work add escrows/single-release
Installs only single-release escrow blocks
💡 Pro Tip: Hierarchical Installation
The deeper you go in the folder structure, the more specific the blocks become. Start with parent directories for comprehensive functionality, then drill down to specific components as needed.