Trustless Work
English
English
  • Welcome
    • Why Escrows Matter
    • Who Should Use This
    • Links
  • ⚒️Core Concepts
    • Smart Escrow Design
      • What does a Smart Escrow "look like"?
    • Roles in Trustless Work
    • Escrow Lifecycle
      • Initiation Phase
      • Funding Phase
      • Complete phase
      • Approval phase
      • Release phase
      • Dispute Resolution
    • USDC: The Stablecoin Powering Trustless Work
    • Stellar & Soroban: The Backbone of Trustless Work
  • 💻Developer Guide
    • 🚀Developer Quickstart
    • Authentication
      • Request Api Key
    • Schema
    • Architecture
    • Stellar Wallets
      • Freighter Wallet
      • Albedo Wallet
      • xBull Wallet
      • Rabet Wallet
      • Lobstr Wallet
      • Hana Wallet
      • Additional Resources
      • Troubleshooting & FAQs
    • How to Get Testnet Tokens
  • API Reference
    • Introduction
    • Types
      • Basic
      • Entities
      • Payloads
      • Responses
      • Errors
    • Single Release Escrow
      • Deploy
      • Fund Escrow
      • Approve Milestone
      • Change Milestone Status
      • Release Funds
      • Dispute Escrow
      • Resolve Dispute
      • Get Escrow
      • Update Escrow
    • Multi Release Escrow
      • Deploy
      • Fund Escrow
      • Approve Milestone
      • Change Milestone Status
      • Release Milestone Funds
      • Dispute Milestone
      • Resolve Milestone Dispute
      • Update Escrow
      • Get Escrow
    • Helpers
      • Set Trustline
      • Send Transaction
      • Get Multiple Escrow Balance
    • 🚀Smart Escrow API
  • React Library
    • Getting Started
    • useSendTransaction
    • useGetEscrow
    • useGetMultipleEscrowBalances
    • useInitializeEscrow
    • useUpdateEscrow
    • useFundEscrow
    • useChangeMilestoneApprovedFlag
    • useChangeMilestoneStatus
    • useReleaseFunds
    • useStartDispute
    • useResolveDispute
  • Templates & Components
    • 🤖Using the dApp
      • Step 1: Accessing the Trustless Work Dapp and Logging In
      • Step 2: Creating a Profile and Requesting an API Key
      • Step 3: Creating an Escrow
      • Step 4: Funding an Escrow
      • Step 5: Marking a Milestone as Done ✅
      • Step 6: Approving the Milestone
      • Step 7: Releasing the Payment
      • Resolving Disputes
    • Integration Demo Project
      • Getting Started
      • Configuration
      • Context API
      • Wallet Setup
      • Trustlines
      • Services
      • Helpers
      • Error Handling
      • Forms
        • Initialize Escrow
        • Fund Escrow
        • Get Escrow
        • Get Multiple Escrow Balances
        • Resolve Dispute
        • Change Milestone Status
        • Change Milestone Flag
        • Change Dispute Flag
        • Release Funds
        • Update Escrow
      • UI Components
        • Pages
        • Cards
        • Tabs
        • Utils
  • Tools & Utilities
  • 🌍Use Cases by Industry
    • Marketplaces & E-commerce
    • Grants, Bounties, and Hackathons
    • P2P Exchanges and OTC Desks
    • Security Deposits
    • Milestone-based Freelance & Contract Work
    • Crowdfunding & Pre-orders
    • DAO Treasury & Working Group Budgets
    • Education & Online Courses
    • Subscription + Performance-based Retainers
  • 🏴‍☠️Community & Contribution
    • 🌎Spotlight: Kindfi
    • 🛣️Roadmap: The Journey Ahead
    • Contributor's Guide
    • 📂Open-Source Templates & Developer Tools
  • 📢Appendix & Archive
    • Contact and Support
    • Notion for Startups
    • Meru
    • ✒️Background & Theory
      • 📘Core Concepts & Escrow Glossary
      • 🎒Historical Context
        • 📜Escrow History:
          • 🗿Ancient to Colonial Era
          • 🏦Banking Era (19th - 20th Century)
          • 💻The Digital Era and Online Escrow
        • ⛓️Blockchain Era: Smart Escrows
Powered by GitBook
LogoLogo

Links

  • Website
On this page
  • Overview
  • Generic Escrow Service

Was this helpful?

Export as PDF
  1. Templates & Components
  2. Integration Demo Project

Services

We set a unique and generic service in order to interact with Trustless Work API.

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.

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.

PreviousTrustlinesNextHelpers

Last updated 20 days ago

Was this helpful?