# Services

## Overview

In order to have a good quality and clean code, we've generated a generic service which interacts with Trustless Work.

## Generic Escrow Service

Every response and payload are completely typed with the entities that we had defined before.

```typescript
import http from "@/config/axios";
import { AxiosError } from "axios";
import { signTransaction } from "../../auth/helpers/stellar-wallet-kit.helper";
import { handleError } from "@/errors/utils/handle-errors";
import { WalletError } from "@/@types/errors.entity";
import { kit } from "@/config/wallet-kit";
import { EscrowRequestResponse } from "@/@types/escrows/escrow-response.entity";
import { EscrowPayloadService } from "@/@types/escrows/escrow-payload.entity";
import { Escrow } from "@/@types/escrows/escrow.entity";
import { HttpMethod } from "@/@types/http.entity";

// Interface defining the required properties for escrow service operations
interface EscrowServiceProps<T extends EscrowPayloadService> {
  payload: T;
  endpoint: string;
  method: HttpMethod;
  requiresSignature?: boolean;
  returnEscrowDataIsRequired?: boolean;
}

/**
 * EscrowService class handles all escrow-related operations
 * including transaction signing and sending to the Stellar network
 */
export class EscrowService {
  private static instance: EscrowService;

  private constructor() {}

  /**
   * Get singleton instance of EscrowService
   */
  public static getInstance(): EscrowService {
    if (!EscrowService.instance) {
      EscrowService.instance = new EscrowService();
    }
    return EscrowService.instance;
  }

  /**
   * Handle GET requests that don't require signature
   */
  private async handleGetRequest<T extends EscrowPayloadService>(
    endpoint: string,
    payload: T
  ): Promise<EscrowRequestResponse> {
    const { data } = await http.get<EscrowRequestResponse>(endpoint, {
      params: payload,
    });
    return data;
  }

  /**
   * Get wallet address for transaction signing
   */
  private async getWalletAddress(): Promise<string> {
    const { address } = await kit.getAddress();
    return address;
  }

  /**
   * Sign transaction using wallet
   */
  private async signTransactionWithWallet(
    unsignedTransaction: string,
    address: string
  ): Promise<string> {
    // Sign the transaction using the Stellar Wallet Kit
    return await signTransaction({ unsignedTransaction, address });
  }

  /**
   * Send signed transaction to the network
   */
  private async sendSignedTransaction(
    signedXdr: string,
    returnEscrowDataIsRequired: boolean
  ): Promise<EscrowRequestResponse> {
    const tx = await http.post("/helper/send-transaction", {
      signedXdr,
      returnEscrowDataIsRequired,
    });
    return tx.data;
  }

  /**
   *
   * Main method to handle escrow operations
   *
   * @Reference URL: https://surli.cc/rlyqso
   *
   * @Flow:
   * 1. Get wallet address
   * 2. Make initial request to get [unsigned transaction]
   * 3. [Sign transaction] with wallet
   * 4. Send [signed transaction] to the network
   * 5. Return [escrow data]
   *
   * @Note:
   * - This method handles both GET and POST requests
   * - It also handles the signing of transactions
   * - It returns the escrow data if required
   * - It handles both HTTP and Wallet errors
   *
   */
  public async execute<T extends EscrowPayloadService>({
    payload,
    endpoint,
    method,
    requiresSignature = true,
    returnEscrowDataIsRequired = true,
  }: EscrowServiceProps<T>): Promise<EscrowRequestResponse | Escrow> {
    try {
      // Handle GET requests that don't require signature
      if (!requiresSignature && method === "get") {
        return await this.handleGetRequest(endpoint, payload);
      }

      // Get wallet address and make initial request
      const address = await this.getWalletAddress();
      const response = await http[method]<EscrowRequestResponse>(
        endpoint,
        payload
      );

      const { unsignedTransaction } = response.data;

      // Validate that we received an unsigned transaction
      if (!unsignedTransaction) {
        throw new Error("No unsigned transaction received from the server");
      }

      // Sign and send transaction
      const signedTxXdr = await this.signTransactionWithWallet(
        unsignedTransaction,
        address
      );

      // Send the signed transaction to the network
      return await this.sendSignedTransaction(
        signedTxXdr,
        returnEscrowDataIsRequired
      );
    } catch (error: unknown) {
      const mappedError = handleError(error as AxiosError | WalletError);
      console.error("Error:", mappedError.message);
      throw new Error(mappedError.message);
    }
  }
}

// Export a singleton instance for easy access
export const escrowService = EscrowService.getInstance();

```

This service will be used in the custom hooks where we send submits with the forms adapted to each Trustless Work endpoint.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.trustlesswork.com/trustless-work/v2-en/oss-dapps/escrow-lab/services.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
