Servicios

Establecimos un servicio único y genérico para interactuar con la API de Trustless Work.

Resumen

Con el fin de tener un código de buena calidad y limpio, hemos generado un servicio genérico que interactúa con Trustless Work.

Servicio genérico de escrow

Cada respuesta y payload están completamente tipados con las entidades que habíamos definido antes.

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";

// Interfaz que define las propiedades requeridas para las operaciones del servicio de escrow
interface EscrowServiceProps<T extends EscrowPayloadService> {
  payload: T;
  endpoint: string;
  method: HttpMethod;
  requiresSignature?: boolean;
  returnEscrowDataIsRequired?: boolean;
}

/**
 * La clase EscrowService maneja todas las operaciones relacionadas con escrow
 * incluidos la firma de transacciones y el envío a la red Stellar
 */
export class EscrowService {
  private static instance: EscrowService;

  private constructor() {}

  /**
   * Obtener la instancia singleton de EscrowService
   */
  public static getInstance(): EscrowService {
    if (!EscrowService.instance) {
      EscrowService.instance = new EscrowService();
    }
    return EscrowService.instance;
  }

  /**
   * Manejar solicitudes GET que no requieren firma
   */
  private async handleGetRequest<T extends EscrowPayloadService>(
    endpoint: string,
    payload: T
  ): Promise<EscrowRequestResponse> {
    const { data } = await http.get<EscrowRequestResponse>(endpoint, {
      params: payload,
    });
    return data;
  }

  /**
   * Obtener la dirección de la wallet para la firma de la transacción
   */
  private async getWalletAddress(): Promise<string> {
    const { address } = await kit.getAddress();
    return address;
  }

  /**
   * Firmar la transacción usando la wallet
   */
  private async signTransactionWithWallet(
    unsignedTransaction: string,
    address: string
  ): Promise<string> {
    // Firmar la transacción usando el Stellar Wallet Kit
    return await signTransaction({ unsignedTransaction, address });
  }

  /**
   * Enviar la transacción firmada a la red
   */
  private async sendSignedTransaction(
    signedXdr: string,
    returnEscrowDataIsRequired: boolean
  ): Promise<EscrowRequestResponse> {
    const tx = await http.post("/helper/send-transaction", {
      signedXdr,
      returnEscrowDataIsRequired,
    });
    return tx.data;
  }

  /**
   *
   * Método principal para manejar las operaciones de escrow
   *
   * @Reference URL: https://surli.cc/rlyqso
   *
   * @Flow:
   * 1. Obtener la dirección de la wallet
   * 2. Hacer la solicitud inicial para obtener [transacción sin firmar]
   * 3. [Firmar la transacción] con la wallet
   * 4. Enviar la [transacción firmada] a la red
   * 5. Devolver [datos del escrow]
   *
   * @Nota:
   * - Este método maneja tanto solicitudes GET como POST
   * - También maneja la firma de transacciones
   * - Devuelve los datos del escrow si se requieren
   * - Maneja tanto errores HTTP como de Wallet
   *
   */
  public async execute<T extends EscrowPayloadService>({
    payload,
    endpoint,
    method,
    requiresSignature = true,
    returnEscrowDataIsRequired = true,
  }: EscrowServiceProps<T>): Promise<EscrowRequestResponse | Escrow> {
    try {
      // Manejar solicitudes GET que no requieren firma
      if (!requiresSignature && method === "get") {
        return await this.handleGetRequest(endpoint, payload);
      }

      // Obtener la dirección de la wallet y hacer la solicitud inicial
      const address = await this.getWalletAddress();
      const response = await http[method]<EscrowRequestResponse>(
        endpoint,
        payload
      );

      const { unsignedTransaction } = response.data;

      // Validar que recibimos una transacción sin firmar
      if (!unsignedTransaction) {
        throw new Error("No unsigned transaction received from the server");
      }

      // Firmar y enviar la transacción
      const signedTxXdr = await this.signTransactionWithWallet(
        unsignedTransaction,
        dirección
      );

      // Enviar la transacción firmada a la red
      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);
    }
  }
}

// Exportar una instancia singleton para un acceso fácil
export const escrowService = EscrowService.getInstance();

Este servicio será usado en los hooks personalizados donde enviamos envíos con los formularios adaptados a cada endpoint de Trustless Work.

Última actualización

¿Te fue útil?