diff --git a/public/content-script.js b/public/content-script.js index 28c717b..e84cd7d 100644 --- a/public/content-script.js +++ b/public/content-script.js @@ -49,7 +49,6 @@ document.addEventListener('qortalExtensionRequests', async (event) => { } }); } else if (type === 'REQUEST_CONNECTION') { - console.log('REQUEST_CONNECTION') const hostname = window.location.hostname chrome?.runtime?.sendMessage({ action: "connection", payload: { hostname @@ -106,8 +105,9 @@ document.addEventListener('qortalExtensionRequests', async (event) => { } chrome?.runtime?.sendMessage({ action: "buyOrder", payload: { - qortalAtAddress: payload.qortalAtAddress, - hostname + qortalAtAddresses: payload.qortalAtAddresses, + hostname, + useLocal: payload?.useLocal }, timeout}, (response) => { if (response.error) { @@ -153,6 +153,36 @@ document.addEventListener('qortalExtensionRequests', async (event) => { })); } }); + } else if(type === 'CHECK_IF_LOCAL'){ + + + const hostname = window.location.hostname + const res = await connection(hostname) + if(!res){ + document.dispatchEvent(new CustomEvent('qortalExtensionResponses', { + detail: { type: "USER_INFO", data: { + error: "Not authorized" + }, requestId } + })); + return + } + chrome?.runtime?.sendMessage({ action: "checkLocal", payload: { + hostname + }, timeout }, (response) => { + + if (response.error) { + document.dispatchEvent(new CustomEvent('qortalExtensionResponses', { + detail: { type: "CHECK_IF_LOCAL", data: { + error: response.error + }, requestId } + })); + } else { + // Include the requestId in the detail when dispatching the response + document.dispatchEvent(new CustomEvent('qortalExtensionResponses', { + detail: { type: "CHECK_IF_LOCAL", data: response, requestId } + })); + } + }); } else if (type === 'REQUEST_AUTHENTICATION') { const hostname = window.location.hostname const res = await connection(hostname) diff --git a/src/App.tsx b/src/App.tsx index 25e21db..44d7c5d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -236,7 +236,7 @@ export const getArbitraryEndpointReact = () => { if (globalApiKey) { - return `/arbitrary/resources/searchsimple`; + return `/arbitrary/resources/search`; } else { return `/arbitrary/resources/searchsimple`; } @@ -688,6 +688,7 @@ function App() { crosschainAtInfo: requestBuyOrder?.crosschainAtInfo, interactionId: requestBuyOrder?.interactionId, isDecline: true, + useLocal: requestBuyOrder?.useLocal }, }, (response) => { @@ -705,6 +706,7 @@ function App() { crosschainAtInfo: requestBuyOrder?.crosschainAtInfo, interactionId: requestBuyOrder?.interactionId, isDecline: false, + useLocal: requestBuyOrder?.useLocal }, }, (response) => { @@ -959,6 +961,11 @@ function App() { setMemberGroups([]) }; + function roundUpToDecimals(number, decimals = 8) { + const factor = Math.pow(10, decimals); // Create a factor based on the number of decimals + return Math.ceil(+number * factor) / factor; + } + const authenticateWallet = async () => { try { setIsLoading(true); @@ -1595,7 +1602,7 @@ function App() { {/* {extState !== "not-authenticated" && ( )} */} - {extState === "authenticated" && ( + {extState === "authenticated" && isMainWindow && ( The Application

{" "} {requestBuyOrder?.hostname}

- is requesting a buy order + is requesting {requestBuyOrder?.crosschainAtInfo?.length} {`buy order${requestBuyOrder?.crosschainAtInfo.length === 1 ? '' : 's'}`} - {+requestBuyOrder?.crosschainAtInfo?.qortAmount} QORT + {requestBuyOrder?.crosschainAtInfo?.reduce((latest, cur)=> { + return latest + +cur?.qortAmount + }, 0)} QORT - {requestBuyOrder?.crosschainAtInfo?.expectedForeignAmount}{" "} - {requestBuyOrder?.crosschainAtInfo?.foreignBlockchain} + {roundUpToDecimals(requestBuyOrder?.crosschainAtInfo?.reduce((latest, cur)=> { + return latest + +cur?.expectedForeignAmount + }, 0))} + {` ${requestBuyOrder?.crosschainAtInfo?.[0]?.foreignBlockchain}`} {/* diff --git a/src/background.ts b/src/background.ts index 8c74424..00ceffc 100644 --- a/src/background.ts +++ b/src/background.ts @@ -25,6 +25,7 @@ import PhraseWallet from "./utils/generateWallet/phrase-wallet"; import { RequestQueueWithPromise } from "./utils/queue/queue"; import { validateAddress } from "./utils/validateAddress"; import { Sha256 } from "asmcrypto.js"; +import { TradeBotRespondMultipleRequest } from "./transactions/TradeBotRespondMultipleRequest"; let lastGroupNotification; export const groupApi = "https://ext-node.qortal.link"; @@ -112,7 +113,7 @@ const getApiKeyFromStorage = async () => { const getArbitraryEndpoint = async () => { const apiKey = await getApiKeyFromStorage(); // Retrieve apiKey asynchronously if (apiKey) { - return `/arbitrary/resources/searchsimple`; + return `/arbitrary/resources/search`; } else { return `/arbitrary/resources/searchsimple`; } @@ -963,6 +964,13 @@ async function getTradeInfo(qortalAtAddress) { const data = await response.json(); return data; } +async function getTradesInfo(qortalAtAddresses) { + // Use Promise.all to fetch data for all addresses concurrently + const trades = await Promise.all( + qortalAtAddresses.map((address) => getTradeInfo(address)) + ); + return trades; // Return the array of trade info objects +} async function getBalanceInfo() { const wallet = await getSaveWallet(); @@ -1467,7 +1475,7 @@ async function sendChat({ qortAddress, recipientPublicKey, message }) { const hasEnoughBalance = +balance < 4 ? false : true; const difficulty = 8; const jsonData = { - atAddress: message.atAddress, + addresses: message.addresses, foreignKey: message.foreignKey, receivingAddress: message.receivingAddress, }; @@ -1714,15 +1722,80 @@ async function decryptDirectFunc({ messages, involvingAddress }) { return holdMessages; } -async function createBuyOrderTx({ crosschainAtInfo }) { +async function createBuyOrderTx({ crosschainAtInfo, useLocal }) { try { + if(useLocal){ + const wallet = await getSaveWallet(); + + const address = wallet.address0; + + const resKeyPair = await getKeyPair(); + const parsedData = JSON.parse(resKeyPair); + const message = { + addresses: crosschainAtInfo.map((order)=> order.qortalAtAddress), + foreignKey: parsedData.ltcPrivateKey, + receivingAddress: address, + }; + let responseVar + const txn = new TradeBotRespondMultipleRequest().createTransaction(message) + const apiKey = await getApiKeyFromStorage(); + const responseFetch = await fetch(`http://127.0.0.1:12391/crosschain/tradebot/respondmultiple?apiKey=${apiKey}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(txn), + }); + + const res = await responseFetch.json(); + + if(res === false){ + responseVar = { response: "Unable to execute buy order", success: false }; + } else { + responseVar = { response: res, success: true }; + } + const { response, success } = responseVar + let responseMessage; + if (success) { + responseMessage = { + callResponse: response, + extra: { + message: 'Transaction processed successfully!', + atAddresses: crosschainAtInfo.map((order)=> order.qortalAtAddress), + + } + }; + } else { + responseMessage = { + callResponse: 'ERROR', + extra: { + message: response, + atAddresses: crosschainAtInfo.map((order)=> order.qortalAtAddress), + + } + }; + } + + setTimeout(() => { + chrome.tabs.query({}, function (tabs) { + tabs.forEach((tab) => { + chrome.tabs.sendMessage(tab.id, { + type: "RESPONSE_FOR_TRADES", + message: responseMessage, + }); + }); + }); + }, 5000); + + return + } const wallet = await getSaveWallet(); const address = wallet.address0; const resKeyPair = await getKeyPair(); const parsedData = JSON.parse(resKeyPair); const message = { - atAddress: crosschainAtInfo.qortalAtAddress, + addresses: crosschainAtInfo.map((order)=> order.qortalAtAddress), foreignKey: parsedData.ltcPrivateKey, receivingAddress: address, }; @@ -1740,7 +1813,7 @@ async function createBuyOrderTx({ crosschainAtInfo }) { }); if (res?.encryptedMessageToBase58) { return { - atAddress: crosschainAtInfo.qortalAtAddress, + atAddresses: crosschainAtInfo.map((order)=> order.qortalAtAddress), encryptedMessageToBase58: res?.encryptedMessageToBase58, node: buyTradeNodeBaseUrl, qortAddress: address, @@ -1751,7 +1824,7 @@ async function createBuyOrderTx({ crosschainAtInfo }) { }; } return { - atAddress: crosschainAtInfo.qortalAtAddress, + atAddresses: crosschainAtInfo.map((order)=> order.qortalAtAddress), chatSignature: res?.signature, node: buyTradeNodeBaseUrl, qortAddress: address, @@ -2237,6 +2310,7 @@ async function fetchMessagesForBuyOrders(apiCall, signature, senderPublicKey) { try { const response = await fetch(apiCall); let data = await response.json(); + data = data.filter( (item) => !triedChatMessage.includes(item.signature) ); @@ -2250,7 +2324,7 @@ async function fetchMessagesForBuyOrders(apiCall, signature, senderPublicKey) { privateKey: uint8PrivateKey, publicKey: uint8PublicKey, }; - + const decodedMessage = decryptChatMessage( encodedMessageObj.data, keyPair.privateKey, @@ -2427,6 +2501,12 @@ async function setChatHeads(data) { }); } +async function checkLocalFunc(){ + const apiKey = await getApiKeyFromStorage() + return !!apiKey + +} + async function getTempPublish() { const wallet = await getSaveWallet(); const address = wallet.address0; @@ -3349,8 +3429,8 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => { break; case "buyOrder": { - const { qortalAtAddress, hostname } = request.payload; - getTradeInfo(qortalAtAddress) + const { qortalAtAddresses, hostname, useLocal } = request.payload; + getTradesInfo(qortalAtAddresses) .then((crosschainAtInfo) => { const popupUrl = chrome.runtime.getURL( "index.html?secondary=true" @@ -3420,6 +3500,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => { hostname, crosschainAtInfo, interactionId, + useLocal }, }); }, 500); @@ -3665,7 +3746,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => { break; case "buyOrderConfirmation": { - const { crosschainAtInfo, isDecline } = request.payload; + const { crosschainAtInfo, isDecline, useLocal } = request.payload; const interactionId2 = request.payload.interactionId; // Retrieve the stored sendResponse callback const originalSendResponse = pendingResponses.get(interactionId2); @@ -3677,7 +3758,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => { pendingResponses.delete(interactionId2); return; } - createBuyOrderTx({ crosschainAtInfo }) + createBuyOrderTx({ crosschainAtInfo, useLocal }) .then((res) => { sendResponse(true); originalSendResponse(res); @@ -3839,6 +3920,19 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => { resumeAllQueues(); sendResponse(true); + break; + } + case "checkLocal": { + checkLocalFunc() + .then((res) => { + sendResponse(res); + }) + .catch((error) => { + console.error(error.message); + sendResponse({ error: error.message }); + }); + + break; } case "decryptSingleForPublishes": { @@ -4037,7 +4131,6 @@ chrome.action?.onClicked?.addListener((tab) => { chrome.windows.getAll( { populate: true, windowTypes: ["popup"] }, (windows) => { - console.log("windows", windows); // Attempt to find an existing popup window that has a tab with the correct URL const existingPopup = windows.find((w) => { return ( @@ -4046,7 +4139,6 @@ chrome.action?.onClicked?.addListener((tab) => { ); }); if (existingPopup) { - console.log("Focusing existing popup window", existingPopup.id); // If the popup exists but is minimized or not focused, focus it if (isMobile) { @@ -4067,7 +4159,6 @@ chrome.action?.onClicked?.addListener((tab) => { }); } } else { - console.log("No existing popup, creating new window..."); // No existing popup found, restore the saved bounds or create a new one restoreWindowBounds((savedBounds) => { chrome.system.display.getInfo((displays) => { diff --git a/src/transactions/TradeBotRespondMultipleRequest.ts b/src/transactions/TradeBotRespondMultipleRequest.ts new file mode 100644 index 0000000..a7eb4d8 --- /dev/null +++ b/src/transactions/TradeBotRespondMultipleRequest.ts @@ -0,0 +1,42 @@ +// @ts-nocheck + +/** + * CrossChain - TradeBot Respond Multiple Request (Buy Action) + * + * These are special types of transactions (JSON ENCODED) + */ + +export class TradeBotRespondMultipleRequest { + constructor() { + // ... + } + + createTransaction(txnReq) { + this.addresses(txnReq.addresses) + this.foreignKey(txnReq.foreignKey) + this.receivingAddress(txnReq.receivingAddress) + + return this.txnRequest() + } + + addresses(addresses) { + this._addresses = addresses + } + + foreignKey(foreignKey) { + this._foreignKey = foreignKey + } + + receivingAddress(receivingAddress) { + this._receivingAddress = receivingAddress + } + + txnRequest() { + return { + addresses: this._addresses, + foreignKey: this._foreignKey, + receivingAddress: this._receivingAddress + } + } +} +