Skip to content

Commit

Permalink
Fixing bug
Browse files Browse the repository at this point in the history
  • Loading branch information
diyahir committed Mar 30, 2024
1 parent a736c37 commit 7b2ece2
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 31 deletions.
13 changes: 8 additions & 5 deletions packages/nextjs/hooks/useWebSocket.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useRef, useState } from "react";
import { InvoiceRequest, InvoiceResponse, ServerStatus } from "~~/types/utils";
import { ConnectionResponse, InvoiceRequest, InvoiceResponse, ServerStatus } from "~~/types/utils";

export const useWebSocket = (url: string) => {
const socket = useRef<WebSocket | null>(null);
Expand Down Expand Up @@ -41,12 +41,15 @@ export const useWebSocket = (url: string) => {
socket.current.onerror = event => setError(event);
socket.current.onmessage = event => {
try {
const responseData: InvoiceResponse = JSON.parse(event.data);
if (responseData.status) {
setStatus(responseData.status as ServerStatus);
const responseData: ConnectionResponse | InvoiceResponse = JSON.parse(event.data);
if (responseData && "serverStatus" in responseData) {
setStatus(responseData.serverStatus as ServerStatus);
return;
}
if (responseData && "status" in responseData) {
setData(responseData);
return;
}
setData(responseData);
} catch (err) {
console.error("Failed to parse message", err);
}
Expand Down
4 changes: 4 additions & 0 deletions packages/nextjs/types/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export interface InvoiceResponse {
message: string;
}

export interface ConnectionResponse {
serverStatus: ServerStatus;
}

export enum ServerStatus {
ACTIVE = "ACTIVE",
INACTIVE = "INACTIVE",
Expand Down
70 changes: 44 additions & 26 deletions packages/server/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dotenv.config();
// Verify environment variables
const { PORT, LND_MACAROON, LND_SOCKET, RPC_URL, LSP_PRIVATE_KEY, CHAIN_ID } =
process.env;
if ( !RPC_URL || !LSP_PRIVATE_KEY || !CHAIN_ID) {
if (!RPC_URL || !LSP_PRIVATE_KEY || !CHAIN_ID) {
console.error("Missing environment variables");
process.exit(1);
}
Expand All @@ -39,7 +39,9 @@ export type CachedPayment = {
contractId: string;
secret: string;
};

let cachedPayments: CachedPayment[] = [];
let pendingContracts: string[] = [];
// ideally this should be stored in a database, but for the sake of simplicity we are using an in-memory cache

console.log(`RPC Provider is running on ${RPC_URL}`);
Expand All @@ -49,17 +51,33 @@ console.log(`LSP Address: ${signer.address}`);
wss.on("connection", (ws: WebSocket) => {
const serverStatus = process.env.LND_MACAROON ? "ACTIVE" : "MOCK";
console.log("Client connected");
ws.send(JSON.stringify({ status: serverStatus, message: "Connected to server" }));
ws.send(
JSON.stringify({
serverStatus: serverStatus,
message: "Connected to server",
})
);

ws.on("message", async (message: string) => {
console.log("Received message:", message);
const request: InvoiceRequest = JSON.parse(message);
if (pendingContracts.includes(request.contractId)) {
ws.send(
JSON.stringify({
status: "error",
message: "Contract is already being processed.",
})
);
return;
}
pendingContracts.push(request.contractId);
try {
const request: InvoiceRequest = JSON.parse(message);
await processInvoiceRequest(request, ws);
} catch (error) {
console.error("Error processing message:", error);
ws.send(JSON.stringify({ status: "error", message: "Invalid request" }));
}
pendingContracts = pendingContracts.filter((c) => c !== request.contractId);
});

ws.on("close", () => console.log("Client disconnected"));
Expand All @@ -75,22 +93,24 @@ async function processInvoiceRequest(request: InvoiceRequest, ws: WebSocket) {

console.log("Invoice Request Received:", request);

// Check if LND_MACAROON and LND_SOCKET are empty to simulate mock mode
if (!process.env.LND_MACAROON && !process.env.LND_SOCKET) {
console.log("Mock Server Mode: Simulating payment success");

// Simulate processing delay
await new Promise(resolve => setTimeout(resolve, 1000)); // 1 second delay for realism

// Directly respond with a simulated success message
ws.send(JSON.stringify({
// Check if LND_MACAROON and LND_SOCKET are empty to simulate mock mode
if (!process.env.LND_MACAROON && !process.env.LND_SOCKET) {
console.log("Mock Server Mode: Simulating payment success");

// Simulate processing delay
await new Promise((resolve) => setTimeout(resolve, 1000)); // 1 second delay for realism

// Directly respond with a simulated success message
ws.send(
JSON.stringify({
status: "success",
message: "Invoice paid successfully in mock mode.",
}));

// Exit early since we're in mock mode
return;
}
})
);

// Exit early since we're in mock mode
return;
}

try {
const options = { gasPrice: ethers.parseUnits("0.001", "gwei") };
Expand Down Expand Up @@ -135,10 +155,14 @@ async function processInvoiceRequest(request: InvoiceRequest, ws: WebSocket) {
max_fee: providerConfig.maxLNFee,
});
console.log("Payment Response:", paymentResponse);

ws.send(
JSON.stringify({
status: "success",
message: "Invoice paid successfully.",
})
);
// Critical point, if this withdraw fails, the LSP will lose funds
// We should cache the paymentResponse.secret and request.contractId and retry the withdrawal if it fails

await htlcContract
.withdraw(request.contractId, "0x" + paymentResponse.secret, options)
.then((tx: any) => {
Expand All @@ -151,13 +175,7 @@ async function processInvoiceRequest(request: InvoiceRequest, ws: WebSocket) {
secret: paymentResponse.secret,
});
});

ws.send(
JSON.stringify({
status: "success",
message: "Invoice paid successfully.",
})
);
console.log("Payment processed successfully");
} catch (error) {
console.error("Error during invoice processing:", error);
ws.send(
Expand Down

0 comments on commit 7b2ece2

Please sign in to comment.