serverServiços

Definimos um serviço único e genérico para interagir com a API da Trustless Work.

Visão geral

Para ter um código de boa qualidade e limpo, geramos um serviço genérico que interage com o Trustless Work.

Serviço Genérico de Escrow

Cada resposta e payload são completamente tipados com as entidades que definimos anteriormente.

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 definindo as propriedades exigidas para operações do serviço de escrow
interface EscrowServiceProps<T extends EscrowPayloadService> {
  payload: T;
  endpoint: string;
  method: HttpMethod;
  requiresSignature?: boolean;
  returnEscrowDataIsRequired?: boolean;
}

/**
 * A classe EscrowService lida com todas as operações relacionadas a escrow
 * incluindo a assinatura de transações e envio para a rede Stellar
 */
export class EscrowService {
  private static instance: EscrowService;

  private constructor() {}

  /**
   * Obtém a instância singleton de EscrowService
   */
  public static getInstance(): EscrowService {
    if (!EscrowService.instance) {
      EscrowService.instance = new EscrowService();
    }
    return EscrowService.instance;
  }

  /**
   * Manipula requisições GET que não requerem assinatura
   */
  private async handleGetRequest<T extends EscrowPayloadService>(
    endpoint: string,
    payload: T
  ): Promise<EscrowRequestResponse> {
    const { data } = await http.get<EscrowRequestResponse>(endpoint, {
      params: payload,
    });
    return data;
  }

  /**
   * Obtém o endereço da carteira para assinatura da transação
   */
  private async getWalletAddress(): Promise<string> {
    const { address } = await kit.getAddress();
    return address;
  }

  /**
   * Assina a transação usando a carteira
   */
  private async signTransactionWithWallet(
    unsignedTransaction: string,
    address: string
  ): Promise<string> {
    // Assina a transação usando o Stellar Wallet Kit
    return await signTransaction({ unsignedTransaction, address });
  }

  /**
   * Envia a transação assinada para a rede
   */
  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 lidar com operações de escrow
   *
   * @Referência URL: https://surli.cc/rlyqso
   *
   * @Fluxo:
   * 1. Obter o endereço da carteira
   * 2. Fazer a requisição inicial para obter [transação não assinada]
   * 3. [Assinar a transação] com a carteira
   * 4. Enviar a [transação assinada] para a rede
   * 5. Retornar [dados do escrow]
   *
   * @Note:
   * - Este método lida tanto com requisições GET quanto POST
   * - Ele também cuida da assinatura das transações
   * - Retorna os dados do escrow se necessário
   * - Trata tanto erros HTTP quanto erros da Carteira
   *
   */
  public async execute<T extends EscrowPayloadService>({
    payload,
    endpoint,
    method,
    requiresSignature = true,
    returnEscrowDataIsRequired = true,
  }: EscrowServiceProps<T>): Promise<EscrowRequestResponse | Escrow> {
    try {
      // Manipula requisições GET que não requerem assinatura
      if (!requiresSignature && method === "get") {
        return await this.handleGetRequest(endpoint, payload);
      }

      // Obtém o endereço da carteira e faz a requisição inicial
      const address = await this.getWalletAddress();
      const response = await http[method]<EscrowRequestResponse>(
        endpoint,
        payload
      );

      const { unsignedTransaction } = response.data;

      // Valida que recebemos uma transação não assinada
      if (!unsignedTransaction) {
        throw new Error("Nenhuma transação não assinada recebida do servidor");
      }

      // Assina e envia a transação
      const signedTxXdr = await this.signTransactionWithWallet(
        unsignedTransaction,
        endereço
      );

      // Envia a transação assinada para a rede
      return await this.sendSignedTransaction(
        signedTxXdr,
        returnEscrowDataIsRequired
      );
    } catch (error: unknown) {
      const mappedError = handleError(error as AxiosError | WalletError);
      console.error("Erro:", mappedError.message);
      throw new Error(mappedError.message);
    }
  }
}

// Exporta uma instância singleton para fácil acesso
export const escrowService = EscrowService.getInstance();

Este serviço será usado nos hooks personalizados onde enviamos submissões com os formulários adaptados a cada endpoint do Trustless Work.

Atualizado