diff --git a/src/background.ts b/src/background.ts index 2398e55..fbd41df 100644 --- a/src/background.ts +++ b/src/background.ts @@ -1309,7 +1309,7 @@ export async function handleActiveGroupDataFromSocket({ groups, directs }) { } catch (error) {} } -async function sendChat({ qortAddress, recipientPublicKey, message }) { +async function sendChatForBuyOrder({ qortAddress, recipientPublicKey, message }) { let _reference = new Uint8Array(64); self.crypto.getRandomValues(_reference); @@ -1350,13 +1350,7 @@ async function sendChat({ qortAddress, recipientPublicKey, message }) { isText: 1, }); if (!hasEnoughBalance) { - const _encryptedMessage = tx._encryptedMessage; - const encryptedMessageToBase58 = Base58.encode(_encryptedMessage); - return { - encryptedMessageToBase58, - signature: "id-" + Date.now() + "-" + Math.floor(Math.random() * 1000), - reference, - }; + throw new Error('You must have at least 4 QORT to trade using the gateway.') } const path = `${import.meta.env.BASE_URL}memory-pow.wasm.full`; @@ -1587,7 +1581,7 @@ export async function decryptDirectFunc({ messages, involvingAddress }) { return holdMessages; } -async function createBuyOrderTx({ crosschainAtInfo, useLocal }) { +export async function createBuyOrderTx({ crosschainAtInfo, useLocal }) { try { if (useLocal) { const wallet = await getSaveWallet(); @@ -1597,7 +1591,7 @@ async function createBuyOrderTx({ crosschainAtInfo, useLocal }) { const resKeyPair = await getKeyPair(); const parsedData = resKeyPair; const message = { - addresses: crosschainAtInfo.map((order) => order.qortalAtAddress), + addresses: crosschainAtInfo.map((order)=> order.qortalAtAddress), foreignKey: parsedData.ltcPrivateKey, receivingAddress: address, }; @@ -1607,7 +1601,7 @@ async function createBuyOrderTx({ crosschainAtInfo, useLocal }) { ); const apiKey = await getApiKeyFromStorage(); const responseFetch = await fetch( - `${apiKey?.url}/crosschain/tradebot/respondmultiple?apiKey=${apiKey?.apikey}`, + `http://127.0.0.1:12391/crosschain/tradebot/respondmultiple?apiKey=${apiKey?.apikey}`, { method: "POST", headers: { @@ -1634,7 +1628,9 @@ async function createBuyOrderTx({ crosschainAtInfo, useLocal }) { callResponse: response, extra: { message: "Transaction processed successfully!", - atAddresses: crosschainAtInfo.map((order) => order.qortalAtAddress), + atAddresses: crosschainAtInfo.map((order)=> order.qortalAtAddress), + senderAddress: address, + node: 'http://127.0.0.1:12391' }, }; } else { @@ -1642,23 +1638,14 @@ async function createBuyOrderTx({ crosschainAtInfo, useLocal }) { callResponse: "ERROR", extra: { message: response, - atAddresses: crosschainAtInfo.map((order) => order.qortalAtAddress), + atAddresses: crosschainAtInfo.map((order)=> order.qortalAtAddress), + senderAddress: address, + node: 'http://127.0.0.1:12391' }, }; } - // setTimeout(() => { - // chrome.tabs.query({}, function (tabs) { - // tabs.forEach((tab) => { - // chrome.tabs.sendMessage(tab.id, { - // type: "RESPONSE_FOR_TRADES", - // message: responseMessage, - // }); - // }); - // }); - // }, 5000); - - return; + return responseMessage } const wallet = await getSaveWallet(); const address = wallet.address0; @@ -1666,40 +1653,56 @@ async function createBuyOrderTx({ crosschainAtInfo, useLocal }) { const resKeyPair = await getKeyPair(); const parsedData = resKeyPair; const message = { - addresses: crosschainAtInfo.map((order) => order.qortalAtAddress), + addresses: crosschainAtInfo.map((order)=> order.qortalAtAddress), foreignKey: parsedData.ltcPrivateKey, receivingAddress: address, }; - const res = await sendChat({ + const res = await sendChatForBuyOrder({ qortAddress: proxyAccountAddress, recipientPublicKey: proxyAccountPublicKey, message, }); if (res?.signature) { - listenForChatMessageForBuyOrder({ + let responseMessage; + + const message = await listenForChatMessageForBuyOrder({ nodeBaseUrl: buyTradeNodeBaseUrl, senderAddress: proxyAccountAddress, senderPublicKey: proxyAccountPublicKey, signature: res?.signature, }); - if (res?.encryptedMessageToBase58) { - return { - atAddresses: crosschainAtInfo.map((order) => order.qortalAtAddress), - encryptedMessageToBase58: res?.encryptedMessageToBase58, - node: buyTradeNodeBaseUrl, - qortAddress: address, - chatSignature: res?.signature, - senderPublicKey: parsedData.publicKey, - sender: address, - reference: res?.reference, - }; + // const status = response.callResponse === true ? 'trade-ongoing' : 'trade-failed' + // if (res?.encryptedMessageToBase58) { + // return { + // atAddresses: crosschainAtInfo.map((order) => order.qortalAtAddress), + // encryptedMessageToBase58: res?.encryptedMessageToBase58, + // node: buyTradeNodeBaseUrl, + // qortAddress: address, + // chatSignature: res?.signature, + // senderPublicKey: parsedData.publicKey, + // sender: address, + // reference: res?.reference, + // response.callResponse + // }; + // } + // return { + // atAddresses: crosschainAtInfo.map((order) => order.qortalAtAddress), + // chatSignature: res?.signature, + // node: buyTradeNodeBaseUrl, + // qortAddress: address, + // }; + responseMessage = { + callResponse: message.callResponse, + extra: { + message: message?.extra?.message, + senderAddress: address, + node: buyTradeNodeBaseUrl, + atAddresses: crosschainAtInfo.map((order)=> order.qortalAtAddress), + }, + encryptedMessageToBase58 } - return { - atAddresses: crosschainAtInfo.map((order) => order.qortalAtAddress), - chatSignature: res?.signature, - node: buyTradeNodeBaseUrl, - qortAddress: address, - }; + + return responseMessage } else { throw new Error("Unable to send buy order message"); } diff --git a/src/components/Apps/useQortalMessageListener.tsx b/src/components/Apps/useQortalMessageListener.tsx index acd5a8d..a5baa6a 100644 --- a/src/components/Apps/useQortalMessageListener.tsx +++ b/src/components/Apps/useQortalMessageListener.tsx @@ -183,7 +183,7 @@ const UIQortalRequests = [ 'GET_WALLET_BALANCE', 'GET_USER_WALLET_INFO', 'GET_CROSSCHAIN_SERVER_INFO', 'GET_TX_ACTIVITY_SUMMARY', 'GET_FOREIGN_FEE', 'UPDATE_FOREIGN_FEE', 'GET_SERVER_CONNECTION_HISTORY', 'SET_CURRENT_FOREIGN_SERVER', - 'ADD_FOREIGN_SERVER', 'REMOVE_FOREIGN_SERVER', 'GET_DAY_SUMMARY' + 'ADD_FOREIGN_SERVER', 'REMOVE_FOREIGN_SERVER', 'GET_DAY_SUMMARY', 'CREATE_TRADE_BUY_ORDER' ]; diff --git a/src/qortalRequests.ts b/src/qortalRequests.ts index d6df7a1..0290da3 100644 --- a/src/qortalRequests.ts +++ b/src/qortalRequests.ts @@ -1,4 +1,4 @@ -import { addForeignServer, addListItems, createPoll, decryptData, deleteListItems, deployAt, encryptData, getCrossChainServerInfo, getDaySummary, getForeignFee, getListItems, getServerConnectionHistory, getTxActivitySummary, getUserAccount, getUserWallet, getUserWalletInfo, getWalletBalance, joinGroup, publishMultipleQDNResources, publishQDNResource, removeForeignServer, saveFile, sendChatMessage, sendCoin, setCurrentForeignServer, updateForeignFee, voteOnPoll } from "./qortalRequests/get"; +import { addForeignServer, addListItems, createBuyOrder, createPoll, decryptData, deleteListItems, deployAt, encryptData, getCrossChainServerInfo, getDaySummary, getForeignFee, getListItems, getServerConnectionHistory, getTxActivitySummary, getUserAccount, getUserWallet, getUserWalletInfo, getWalletBalance, joinGroup, publishMultipleQDNResources, publishQDNResource, removeForeignServer, saveFile, sendChatMessage, sendCoin, setCurrentForeignServer, updateForeignFee, voteOnPoll } from "./qortalRequests/get"; import { getData, storeData } from "./utils/chromeStorage"; @@ -584,6 +584,26 @@ function setLocalStorage(key, data) { } break; } + + case "CREATE_TRADE_BUY_ORDER": { + try { + const res = await createBuyOrder(request.payload, isFromExtension); + event.source.postMessage({ + requestId: request.requestId, + action: request.action, + payload: res, + type: "backgroundMessageResponse", + }, event.origin); + } catch (error) { + event.source.postMessage({ + requestId: request.requestId, + action: request.action, + error: error.message, + type: "backgroundMessageResponse", + }, event.origin); + } + break; + } default: break; diff --git a/src/qortalRequests/get.ts b/src/qortalRequests/get.ts index 66ae7cb..d38e7fc 100644 --- a/src/qortalRequests/get.ts +++ b/src/qortalRequests/get.ts @@ -12,7 +12,8 @@ import { joinGroup as joinGroupFunc, sendQortFee, sendCoin as sendCoinFunc, - isUsingLocal + isUsingLocal, + createBuyOrderTx } from "../background"; import { getNameInfo } from "../backgroundFunctions/encryption"; import { showSaveFilePicker } from "../components/Apps/useQortalMessageListener"; @@ -38,6 +39,10 @@ const dogeFeePerByte = 0.00001000 const dgbFeePerByte = 0.00000010 const rvnFeePerByte = 0.00001125 +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 _createPoll = async ({pollName, pollDescription, options}, isFromExtension) => { const fee = await getFee("CREATE_POLL"); @@ -2387,3 +2392,63 @@ export const sendCoin = async (data, isFromExtension) => { } } }; + + +export const createBuyOrder = async (data, isFromExtension) => { + + const requiredFields = [ + "crosschainAtInfo", + "processType" + ]; + const missingFields: string[] = []; + requiredFields.forEach((field) => { + if (!data[field]) { + missingFields.push(field); + } + }); + if (missingFields.length > 0) { + const missingFieldsString = missingFields.join(", "); + const errorMsg = `Missing fields: ${missingFieldsString}`; + throw new Error(errorMsg); + } + const crosschainAtInfo = data.crosschainAtInfo; + const atAddresses = data.crosschainAtInfo?.map((order)=> order.qortalAtAddress); + const processType = data.processType; + if(processType !== 'local' && processType !== 'gateway'){ + throw new Error('Process Type must be either local or gateway') + } + + try { + const resPermission = await getUserPermission({ + text1: "Do you give this application permission to perform a buy order?", + text2: `${atAddresses?.length}${" "} + ${`buy order${ + atAddresses?.length === 1 ? "" : "s" + }`}`, + text3: `${crosschainAtInfo?.reduce((latest, cur) => { + return latest + +cur?.qortAmount; + }, 0)} QORT FOR ${roundUpToDecimals( + crosschainAtInfo?.reduce((latest, cur) => { + return latest + +cur?.foreignAmount; + }, 0) + )} + ${` ${crosschainAtInfo?.[0]?.foreignBlockchain}`}`, + highlightedText: `Using ${processType}`, + fee: '' + }, isFromExtension); + const { accepted } = resPermission; + if (accepted) { + const resBuyOrder = await createBuyOrderTx( + { + crosschainAtInfo, + useLocal: processType === 'local' ? true : false + } + ); + return resBuyOrder; + } else { + throw new Error("User declined request"); + } + } catch (error) { + throw new Error(error?.message || "Failed to submit trade order."); + } +}; \ No newline at end of file