mirror of
https://github.com/Qortal/qortal-mobile.git
synced 2025-03-15 04:12:32 +00:00
added qortalrequests for trade
This commit is contained in:
parent
2638b24def
commit
7892a9a26d
28
src/App.tsx
28
src/App.tsx
@ -704,6 +704,9 @@ function App() {
|
||||
const qortalRequestPermissonFromExtension = async (message, event) => {
|
||||
if (message.action === "QORTAL_REQUEST_PERMISSION") {
|
||||
try {
|
||||
if(message?.payload?.checkbox1){
|
||||
qortalRequestCheckbox1Ref.current = message?.payload?.checkbox1
|
||||
}
|
||||
await showQortalRequestExtension(message?.payload);
|
||||
if (qortalRequestCheckbox1Ref.current) {
|
||||
event.source.postMessage(
|
||||
@ -1479,10 +1482,12 @@ function App() {
|
||||
textDecoration: "underline",
|
||||
}}
|
||||
onClick={async () => {
|
||||
await Browser.open({ url: "https://www.qort.trade" });
|
||||
executeEvent("addTab", { data: { service: 'APP', name: 'q-trade' } });
|
||||
executeEvent("open-apps-mode", { });
|
||||
setIsOpenDrawerProfile(false);
|
||||
}}
|
||||
>
|
||||
Get QORT at qort.trade
|
||||
Get QORT at q-trade
|
||||
</TextP>
|
||||
</AuthenticatedContainerInnerLeft>
|
||||
<AuthenticatedContainerInnerRight>
|
||||
@ -2832,6 +2837,25 @@ await showInfo({
|
||||
<Spacer height="15px" />
|
||||
</>
|
||||
)}
|
||||
{messageQortalRequestExtension?.foreignFee && (
|
||||
<>
|
||||
<Spacer height="15px" />
|
||||
|
||||
<TextP
|
||||
sx={{
|
||||
textAlign: "center",
|
||||
lineHeight: 1.2,
|
||||
fontSize: "16px",
|
||||
fontWeight: "normal",
|
||||
maxWidth: "90%",
|
||||
}}
|
||||
>
|
||||
{"Foreign Fee: "}
|
||||
{messageQortalRequestExtension?.foreignFee}
|
||||
</TextP>
|
||||
<Spacer height="15px" />
|
||||
</>
|
||||
)}
|
||||
{messageQortalRequestExtension?.checkbox1 && (
|
||||
<Box
|
||||
sx={{
|
||||
|
@ -24,6 +24,10 @@ export const sortablePinnedAppsAtom = atom({
|
||||
},{
|
||||
name: 'Qombo',
|
||||
service: 'APP'
|
||||
},
|
||||
{
|
||||
name: 'Q-Trade',
|
||||
service: 'APP'
|
||||
}
|
||||
],
|
||||
});
|
||||
|
@ -117,6 +117,9 @@ export function getProtocol(url) {
|
||||
}
|
||||
}
|
||||
|
||||
export const gateways = ['ext-node.qortal.link']
|
||||
|
||||
|
||||
let lastGroupNotification;
|
||||
export const groupApi = "https://ext-node.qortal.link";
|
||||
export const groupApiSocket = "wss://ext-node.qortal.link";
|
||||
@ -174,6 +177,19 @@ export const clearAllQueues = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const getForeignKey = async (foreignBlockchain)=> {
|
||||
const resKeyPair = await getKeyPair();
|
||||
const parsedData = resKeyPair;
|
||||
|
||||
switch (foreignBlockchain) {
|
||||
case "LITECOIN":
|
||||
return parsedData.ltcPrivateKey
|
||||
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export const pauseAllQueues = () => controlAllQueues("pause");
|
||||
export const resumeAllQueues = () => controlAllQueues("resume");
|
||||
const checkDifference = (createdTimestamp) => {
|
||||
@ -1581,27 +1597,29 @@ export async function decryptDirectFunc({ messages, involvingAddress }) {
|
||||
return holdMessages;
|
||||
}
|
||||
|
||||
export async function createBuyOrderTx({ crosschainAtInfo, useLocal }) {
|
||||
export async function createBuyOrderTx({ crosschainAtInfo, isGateway, foreignBlockchain }) {
|
||||
try {
|
||||
if (useLocal) {
|
||||
|
||||
if (!isGateway) {
|
||||
const wallet = await getSaveWallet();
|
||||
|
||||
const address = wallet.address0;
|
||||
|
||||
const resKeyPair = await getKeyPair();
|
||||
const parsedData = resKeyPair;
|
||||
const message = {
|
||||
addresses: crosschainAtInfo.map((order)=> order.qortalAtAddress),
|
||||
foreignKey: parsedData.ltcPrivateKey,
|
||||
foreignKey: await getForeignKey(foreignBlockchain),
|
||||
receivingAddress: address,
|
||||
};
|
||||
let responseVar;
|
||||
const txn = new TradeBotRespondMultipleRequest().createTransaction(
|
||||
message
|
||||
);
|
||||
const apiKey = await getApiKeyFromStorage();
|
||||
|
||||
|
||||
const url = await createEndpoint('/crosschain/tradebot/respondmultiple')
|
||||
|
||||
const responseFetch = await fetch(
|
||||
`http://127.0.0.1:12391/crosschain/tradebot/respondmultiple?apiKey=${apiKey?.apikey}`,
|
||||
url,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
@ -1630,7 +1648,7 @@ export async function createBuyOrderTx({ crosschainAtInfo, useLocal }) {
|
||||
message: "Transaction processed successfully!",
|
||||
atAddresses: crosschainAtInfo.map((order)=> order.qortalAtAddress),
|
||||
senderAddress: address,
|
||||
node: 'http://127.0.0.1:12391'
|
||||
node: url
|
||||
},
|
||||
};
|
||||
} else {
|
||||
@ -1640,7 +1658,7 @@ export async function createBuyOrderTx({ crosschainAtInfo, useLocal }) {
|
||||
message: response,
|
||||
atAddresses: crosschainAtInfo.map((order)=> order.qortalAtAddress),
|
||||
senderAddress: address,
|
||||
node: 'http://127.0.0.1:12391'
|
||||
node: url
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -1650,58 +1668,39 @@ export async function createBuyOrderTx({ crosschainAtInfo, useLocal }) {
|
||||
const wallet = await getSaveWallet();
|
||||
const address = wallet.address0;
|
||||
|
||||
const resKeyPair = await getKeyPair();
|
||||
const parsedData = resKeyPair;
|
||||
|
||||
const message = {
|
||||
addresses: crosschainAtInfo.map((order)=> order.qortalAtAddress),
|
||||
foreignKey: parsedData.ltcPrivateKey,
|
||||
foreignKey: await getForeignKey(foreignBlockchain),
|
||||
receivingAddress: address,
|
||||
};
|
||||
const res = await sendChatForBuyOrder({
|
||||
qortAddress: proxyAccountAddress,
|
||||
recipientPublicKey: proxyAccountPublicKey,
|
||||
message,
|
||||
atAddresses: crosschainAtInfo.map((order)=> order.qortalAtAddress),
|
||||
});
|
||||
|
||||
|
||||
if (res?.signature) {
|
||||
let responseMessage;
|
||||
|
||||
const message = await listenForChatMessageForBuyOrder({
|
||||
nodeBaseUrl: buyTradeNodeBaseUrl,
|
||||
senderAddress: proxyAccountAddress,
|
||||
senderPublicKey: proxyAccountPublicKey,
|
||||
signature: res?.signature,
|
||||
});
|
||||
// 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
|
||||
}
|
||||
|
||||
const message = await listenForChatMessageForBuyOrder({
|
||||
nodeBaseUrl: buyTradeNodeBaseUrl,
|
||||
senderAddress: proxyAccountAddress,
|
||||
senderPublicKey: proxyAccountPublicKey,
|
||||
signature: res?.signature,
|
||||
});
|
||||
|
||||
const responseMessage = {
|
||||
callResponse: message.callResponse,
|
||||
extra: {
|
||||
message: message?.extra?.message,
|
||||
senderAddress: address,
|
||||
node: buyTradeNodeBaseUrl,
|
||||
atAddresses: crosschainAtInfo.map((order)=> order.qortalAtAddress),
|
||||
}
|
||||
}
|
||||
|
||||
return responseMessage
|
||||
} else {
|
||||
throw new Error("Unable to send buy order message");
|
||||
@ -2306,14 +2305,7 @@ async function listenForChatMessageForBuyOrder({
|
||||
senderPublicKey
|
||||
);
|
||||
|
||||
// chrome.tabs.query({}, function (tabs) {
|
||||
// tabs.forEach((tab) => {
|
||||
// chrome.tabs.sendMessage(tab.id, {
|
||||
// type: "RESPONSE_FOR_TRADES",
|
||||
// message: parsedMessageObj,
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
return parsedMessageObj
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw new Error(error.message);
|
||||
|
@ -105,10 +105,19 @@ export const Apps = ({ mode, setMode, show , myName}) => {
|
||||
// dispatch(setIsLoadingGlobal(false))
|
||||
}
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
getCategories()
|
||||
}, [getCategories]);
|
||||
|
||||
useEffect(() => {
|
||||
getQapps();
|
||||
getCategories()
|
||||
}, [getQapps, getCategories]);
|
||||
|
||||
const interval = setInterval(() => {
|
||||
getQapps();
|
||||
}, 20 * 60 * 1000); // 20 minutes in milliseconds
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [getQapps]);
|
||||
|
||||
const selectedAppInfoFunc = (e) => {
|
||||
const data = e.detail?.data;
|
||||
@ -292,6 +301,7 @@ export const Apps = ({ mode, setMode, show , myName}) => {
|
||||
myName={myName}
|
||||
hasPublishApp={!!(myApp || myWebsite)}
|
||||
categories={categories}
|
||||
getQapps={getQapps}
|
||||
/>
|
||||
|
||||
{mode === "appInfo" && !selectedTab && <AppInfo app={selectedAppInfo} myName={myName} />}
|
||||
|
@ -39,6 +39,7 @@ const officialAppList = [
|
||||
"qombo",
|
||||
"q-fund",
|
||||
"q-shop",
|
||||
"q-trade"
|
||||
];
|
||||
|
||||
const ScrollerStyled = styled('div')({
|
||||
|
@ -26,6 +26,7 @@ import IconClearInput from "../../assets/svgs/ClearInput.svg";
|
||||
import qappDevelopText from "../../assets/svgs/qappDevelopText.svg";
|
||||
import qappDots from "../../assets/svgs/qappDots.svg";
|
||||
import ReturnSVG from '../../assets/svgs/Return.svg'
|
||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||
|
||||
import { Spacer } from "../../common/Spacer";
|
||||
import { AppInfoSnippet } from "./AppInfoSnippet";
|
||||
@ -41,6 +42,7 @@ const officialAppList = [
|
||||
"qombo",
|
||||
"q-fund",
|
||||
"q-shop",
|
||||
"q-trade"
|
||||
];
|
||||
|
||||
const ScrollerStyled = styled('div')({
|
||||
@ -76,7 +78,7 @@ const ScrollerStyled = styled('div')({
|
||||
"-ms-overflow-style": "none",
|
||||
});
|
||||
|
||||
export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, isShow, categories={categories} }) => {
|
||||
export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, isShow, categories, getQapps }) => {
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
const virtuosoRef = useRef();
|
||||
const { rootHeight } = useContext(MyContext);
|
||||
@ -132,6 +134,11 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
gap: '20px',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<AppsSearchContainer>
|
||||
<AppsSearchLeft>
|
||||
<img src={IconSearch} />
|
||||
@ -159,6 +166,21 @@ export const AppsLibrary = ({ availableQapps, setMode, myName, hasPublishApp, i
|
||||
)}
|
||||
</AppsSearchRight>
|
||||
</AppsSearchContainer>
|
||||
<ButtonBase
|
||||
onClick={(e) => {
|
||||
getQapps()
|
||||
}}
|
||||
>
|
||||
<RefreshIcon
|
||||
|
||||
sx={{
|
||||
color: "rgba(250, 250, 250, 0.5)",
|
||||
width: '30px',
|
||||
height: 'auto'
|
||||
}}
|
||||
/>
|
||||
</ButtonBase>
|
||||
</Box>
|
||||
</Box>
|
||||
</AppsWidthLimiter>
|
||||
<Spacer height="25px" />
|
||||
|
@ -183,7 +183,8 @@ 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', 'CREATE_TRADE_BUY_ORDER'
|
||||
'ADD_FOREIGN_SERVER', 'REMOVE_FOREIGN_SERVER', 'GET_DAY_SUMMARY', 'CREATE_TRADE_BUY_ORDER',
|
||||
'CREATE_TRADE_SELL_ORDER', 'CANCEL_TRADE_SELL_ORDER', 'IS_USING_GATEWAY'
|
||||
];
|
||||
|
||||
|
||||
@ -434,7 +435,7 @@ isDOMContentLoaded: false
|
||||
if (event?.data?.requestedHandler !== 'UI') return;
|
||||
|
||||
const sendMessageToRuntime = (message, eventPort) => {
|
||||
window.sendMessage(message.action, message.payload, 60000, message.isExtension)
|
||||
window.sendMessage(message.action, message.payload, 300000, message.isExtension)
|
||||
.then((response) => {
|
||||
if (response.error) {
|
||||
eventPort.postMessage({
|
||||
|
@ -93,7 +93,7 @@ export const MessageDisplay = ({ htmlContent, isReply }) => {
|
||||
if (res) {
|
||||
const { service, name, identifier, path } = res;
|
||||
executeEvent("addTab", { data: { service, name, identifier, path } });
|
||||
executeEvent("open-dev-mode", { });
|
||||
executeEvent("open-apps-mode", { });
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1314,10 +1314,10 @@ export const Group = ({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
subscribeToEvent("open-dev-mode", openDevModeFunc);
|
||||
subscribeToEvent("open-apps-mode", openDevModeFunc);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("open-dev-mode", openDevModeFunc);
|
||||
unsubscribeFromEvent("open-apps-mode", openDevModeFunc);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
@ -17,6 +17,7 @@ import { WalletIcon } from "../../assets/Icons/WalletIcon";
|
||||
import { HubsIcon } from "../../assets/Icons/HubsIcon";
|
||||
import { TradingIcon } from "../../assets/Icons/TradingIcon";
|
||||
import { MessagingIcon } from "../../assets/Icons/MessagingIcon";
|
||||
import { executeEvent } from "../../utils/events";
|
||||
|
||||
const IconWrapper = ({ children, label, color }) => {
|
||||
return (
|
||||
@ -209,7 +210,8 @@ export const MobileFooter = ({
|
||||
/>
|
||||
<BottomNavigationAction
|
||||
onClick={async () => {
|
||||
await Browser.open({ url: 'https://www.qort.trade' });
|
||||
executeEvent("addTab", { data: { service: 'APP', name: 'q-trade' } });
|
||||
executeEvent("open-apps-mode", { });
|
||||
}}
|
||||
|
||||
icon={
|
||||
|
@ -1,4 +1,5 @@
|
||||
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 { gateways, getApiKeyFromStorage } from "./background";
|
||||
import { addForeignServer, addListItems, cancelSellOrder, 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";
|
||||
|
||||
|
||||
@ -18,6 +19,16 @@ function setLocalStorage(key, data) {
|
||||
});
|
||||
}
|
||||
|
||||
export const isRunningGateway = async ()=> {
|
||||
let isGateway = true;
|
||||
const apiKey = await getApiKeyFromStorage();
|
||||
if (apiKey && (apiKey?.url && !gateways.some(gateway => apiKey?.url?.includes(gateway)))) {
|
||||
isGateway = false;
|
||||
}
|
||||
|
||||
return isGateway
|
||||
}
|
||||
|
||||
|
||||
export async function setPermission(key, value) {
|
||||
try {
|
||||
@ -604,6 +615,48 @@ function setLocalStorage(key, data) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "CANCEL_TRADE_SELL_ORDER": {
|
||||
try {
|
||||
const res = await cancelSellOrder(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;
|
||||
}
|
||||
case "IS_USING_GATEWAY": {
|
||||
try {
|
||||
console.log('isusing going')
|
||||
let isGateway = await isRunningGateway()
|
||||
console.log('isGateway', isGateway)
|
||||
event.source.postMessage({
|
||||
requestId: request.requestId,
|
||||
action: request.action,
|
||||
payload: {isGateway},
|
||||
type: "backgroundMessageResponse",
|
||||
}, event.origin);
|
||||
} catch (error) {
|
||||
console.log('isusing going', error)
|
||||
event.source.postMessage({
|
||||
requestId: request.requestId,
|
||||
action: request.action,
|
||||
error: error?.message,
|
||||
type: "backgroundMessageResponse",
|
||||
}, event.origin);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -28,10 +28,12 @@ import {
|
||||
uint8ArrayToBase64,
|
||||
} from "../qdn/encryption/group-encryption";
|
||||
import { publishData } from "../qdn/publish/pubish";
|
||||
import { getPermission, setPermission } from "../qortalRequests";
|
||||
import { getPermission, setPermission, isRunningGateway } from "../qortalRequests";
|
||||
import { createTransaction } from "../transactions/transactions";
|
||||
import { mimeToExtensionMap } from "../utils/memeTypes";
|
||||
|
||||
import TradeBotCreateRequest from "../transactions/TradeBotCreateRequest";
|
||||
import DeleteTradeOffer from "../transactions/TradeBotDeleteRequest";
|
||||
import signTradeBotTransaction from "../transactions/signTradeBotTransaction";
|
||||
|
||||
const btcFeePerByte = 0.00000100
|
||||
const ltcFeePerByte = 0.00000030
|
||||
@ -39,6 +41,13 @@ const dogeFeePerByte = 0.00001000
|
||||
const dgbFeePerByte = 0.00000010
|
||||
const rvnFeePerByte = 0.00001125
|
||||
|
||||
const sellerForeignFee = {
|
||||
'LITECOIN': {
|
||||
value: '~0.00005',
|
||||
ticker: 'LTC'
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@ -1359,22 +1368,30 @@ export const getWalletBalance = async (data, bypassPermission?: boolean, isFromE
|
||||
const errorMsg = `Missing fields: ${missingFieldsString}`;
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
const value = (await getPermission(`qAPPAutoWalletBalance-${data.coin}`)) || false;
|
||||
console.log('value', value)
|
||||
let skip = false;
|
||||
if (value) {
|
||||
skip = true;
|
||||
}
|
||||
let resPermission
|
||||
|
||||
if(!bypassPermission){
|
||||
if(!bypassPermission && !skip){
|
||||
resPermission = await getUserPermission({
|
||||
text1: "Do you give this application permission to fetch your",
|
||||
highlightedText: `${data.coin} balance`,
|
||||
checkbox1: {
|
||||
value: true,
|
||||
label: "Always allow balance to be retrieved automatically",
|
||||
},
|
||||
}, isFromExtension);
|
||||
} else {
|
||||
resPermission = {
|
||||
accepted: false
|
||||
}
|
||||
}
|
||||
const { accepted = false, checkbox1 = false } = resPermission || {};
|
||||
if(resPermission){
|
||||
setPermission(`qAPPAutoWalletBalance-${data.coin}`, checkbox1);
|
||||
}
|
||||
|
||||
const { accepted } = resPermission;
|
||||
|
||||
if (accepted || bypassPermission) {
|
||||
if (accepted || bypassPermission || skip) {
|
||||
let coin = data.coin;
|
||||
const wallet = await getSaveWallet();
|
||||
const address = wallet.address0;
|
||||
@ -1461,7 +1478,7 @@ export const getWalletBalance = async (data, bypassPermission?: boolean, isFromE
|
||||
}
|
||||
};
|
||||
|
||||
const getUserWalletFunc = async (coin) => {
|
||||
export const getUserWalletFunc = async (coin) => {
|
||||
let userWallet = {};
|
||||
const wallet = await getSaveWallet();
|
||||
const address = wallet.address0;
|
||||
@ -2394,11 +2411,13 @@ export const sendCoin = async (data, isFromExtension) => {
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
export const createBuyOrder = async (data, isFromExtension) => {
|
||||
|
||||
const requiredFields = [
|
||||
"crosschainAtInfo",
|
||||
"processType"
|
||||
"foreignBlockchain"
|
||||
];
|
||||
const missingFields: string[] = [];
|
||||
requiredFields.forEach((field) => {
|
||||
@ -2411,12 +2430,10 @@ export const createBuyOrder = async (data, isFromExtension) => {
|
||||
const errorMsg = `Missing fields: ${missingFieldsString}`;
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
const isGateway = await isRunningGateway()
|
||||
const foreignBlockchain = data.foreignBlockchain
|
||||
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({
|
||||
@ -2433,16 +2450,18 @@ export const createBuyOrder = async (data, isFromExtension) => {
|
||||
}, 0)
|
||||
)}
|
||||
${` ${crosschainAtInfo?.[0]?.foreignBlockchain}`}`,
|
||||
highlightedText: `Using ${processType}`,
|
||||
fee: ''
|
||||
highlightedText: `Is using gateway: ${isGateway}`,
|
||||
fee: '',
|
||||
foreignFee: `${sellerForeignFee[foreignBlockchain].value} ${sellerForeignFee[foreignBlockchain].ticker}`
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
if (accepted) {
|
||||
const resBuyOrder = await createBuyOrderTx(
|
||||
{
|
||||
crosschainAtInfo,
|
||||
useLocal: processType === 'local' ? true : false
|
||||
}
|
||||
isGateway,
|
||||
foreignBlockchain
|
||||
}
|
||||
);
|
||||
return resBuyOrder;
|
||||
} else {
|
||||
@ -2451,4 +2470,249 @@ export const createBuyOrder = async (data, isFromExtension) => {
|
||||
} catch (error) {
|
||||
throw new Error(error?.message || "Failed to submit trade order.");
|
||||
}
|
||||
};
|
||||
|
||||
const cancelTradeOfferTradeBot = async (body, keyPair) => {
|
||||
const txn = new DeleteTradeOffer().createTransaction(body)
|
||||
const url = await createEndpoint(`/crosschain/tradeoffer`);
|
||||
const bodyToString = JSON.stringify(txn);
|
||||
|
||||
const deleteTradeBotResponse = await fetch(url, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: bodyToString,
|
||||
});
|
||||
|
||||
if(!deleteTradeBotResponse.ok) throw new Error('Unable to update tradebot')
|
||||
const unsignedTxn = await deleteTradeBotResponse.text()
|
||||
const signedTxnBytes = await signTradeBotTransaction(
|
||||
unsignedTxn,
|
||||
keyPair
|
||||
)
|
||||
const signedBytes = Base58.encode(signedTxnBytes);
|
||||
|
||||
let res
|
||||
try {
|
||||
res = await processTransactionVersion2(signedBytes)
|
||||
} catch (error) {
|
||||
return {
|
||||
error: "Failed to Cancel Sell Order. Try again!",
|
||||
failedTradeBot: {
|
||||
atAddress: body.atAddress,
|
||||
creatorAddress: body.creatorAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
if(res?.error){
|
||||
return {
|
||||
error: "Failed to Cancel Sell Order. Try again!",
|
||||
failedTradeBot: {
|
||||
atAddress: body.atAddress,
|
||||
creatorAddress: body.creatorAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res?.signature){
|
||||
return res
|
||||
} else {
|
||||
throw new Error("Failed to Cancel Sell Order. Try again!")
|
||||
}
|
||||
}
|
||||
const findFailedTradebot = async (createBotCreationTimestamp, body)=> {
|
||||
//wait 5 secs
|
||||
const wallet = await getSaveWallet();
|
||||
const address = wallet.address0;
|
||||
await new Promise((res)=> {
|
||||
setTimeout(() => {
|
||||
res(null)
|
||||
}, 5000);
|
||||
})
|
||||
const url = await createEndpoint(`/crosschain/tradebot?foreignBlockchain=LITECOIN`);
|
||||
|
||||
const tradeBotsReponse = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const data = await tradeBotsReponse.json()
|
||||
const latestItem2 = data
|
||||
.filter(
|
||||
(item) =>
|
||||
item.creatorAddress === address
|
||||
).sort((a, b) => b.timestamp - a.timestamp)[0]
|
||||
const latestItem = data
|
||||
.filter(
|
||||
(item) =>
|
||||
item.creatorAddress === address &&
|
||||
+item.foreignAmount === +body.foreignAmount
|
||||
)
|
||||
.sort((a, b) => b.timestamp - a.timestamp)[0];
|
||||
if (
|
||||
latestItem &&
|
||||
createBotCreationTimestamp - latestItem.timestamp <= 5000 &&
|
||||
createBotCreationTimestamp > latestItem.timestamp // Ensure latestItem's timestamp is before createBotCreationTimestamp
|
||||
) {
|
||||
|
||||
return latestItem
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
const tradeBotCreateRequest = async (body, keyPair)=> {
|
||||
const txn = new TradeBotCreateRequest().createTransaction(body)
|
||||
const url = await createEndpoint(`/crosschain/tradebot/create`);
|
||||
const bodyToString = JSON.stringify(txn);
|
||||
|
||||
const unsignedTxnResponse = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: bodyToString,
|
||||
});
|
||||
if(!unsignedTxnResponse.ok) throw new Error('Unable to create tradebot')
|
||||
const createBotCreationTimestamp = Date.now()
|
||||
const unsignedTxn = await unsignedTxnResponse.text()
|
||||
const signedTxnBytes = await signTradeBotTransaction(
|
||||
unsignedTxn,
|
||||
keyPair
|
||||
)
|
||||
const signedBytes = Base58.encode(signedTxnBytes);
|
||||
|
||||
let res
|
||||
try {
|
||||
res = await processTransactionVersion2(signedBytes)
|
||||
} catch (error) {
|
||||
const findFailedTradeBot = await findFailedTradebot(createBotCreationTimestamp, body)
|
||||
return {
|
||||
error: "Failed to Create Sell Order. Try again!",
|
||||
failedTradeBot: findFailedTradeBot
|
||||
}
|
||||
}
|
||||
|
||||
if (res?.signature){
|
||||
return res
|
||||
} else {
|
||||
throw new Error("Failed to Create Sell Order. Try again!")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const createSellOrder = async (data, isFromExtension) => {
|
||||
|
||||
const requiredFields = [
|
||||
"qortAmount",
|
||||
"foreignBlockchain",
|
||||
"foreignAmount"
|
||||
];
|
||||
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 receivingAddress = await getUserWalletFunc('LTC')
|
||||
try {
|
||||
const resPermission = await getUserPermission({
|
||||
text1: "Do you give this application permission to perform a sell order?",
|
||||
text2: `${data.qortAmount}${" "}
|
||||
${`QORT`}`,
|
||||
text3: `FOR ${data.foreignAmount} ${data.foreignBlockchain}`,
|
||||
fee: '0.02'
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
if (accepted) {
|
||||
const resKeyPair = await getKeyPair()
|
||||
const parsedData = resKeyPair
|
||||
const userPublicKey = parsedData.publicKey
|
||||
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
|
||||
const uint8PublicKey = Base58.decode(parsedData.publicKey);
|
||||
const keyPair = {
|
||||
privateKey: uint8PrivateKey,
|
||||
publicKey: uint8PublicKey,
|
||||
};
|
||||
const response = await tradeBotCreateRequest({
|
||||
creatorPublicKey: userPublicKey,
|
||||
qortAmount: parseFloat(data.qortAmount),
|
||||
fundingQortAmount: parseFloat(data.qortAmount) + 0.001,
|
||||
foreignBlockchain: data.foreignBlockchain,
|
||||
foreignAmount: parseFloat(data.foreignAmount),
|
||||
tradeTimeout: 120,
|
||||
receivingAddress: receivingAddress.address
|
||||
}, keyPair)
|
||||
|
||||
return response
|
||||
|
||||
} else {
|
||||
throw new Error("User declined request");
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(error?.message || "Failed to submit sell order.");
|
||||
}
|
||||
};
|
||||
|
||||
export const cancelSellOrder = async (data, isFromExtension) => {
|
||||
|
||||
const requiredFields = [
|
||||
"qortAmount",
|
||||
"foreignBlockchain",
|
||||
"foreignAmount",
|
||||
"atAddress"
|
||||
];
|
||||
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);
|
||||
}
|
||||
|
||||
try {
|
||||
const fee = await getFee("MESSAGE");
|
||||
|
||||
const resPermission = await getUserPermission({
|
||||
text1: "Do you give this application permission to perform cancel a sell order?",
|
||||
text2: `${data.qortAmount}${" "}
|
||||
${`QORT`}`,
|
||||
text3: `FOR ${data.foreignAmount} ${data.foreignBlockchain}`,
|
||||
fee: fee.fee
|
||||
}, isFromExtension);
|
||||
const { accepted } = resPermission;
|
||||
if (accepted) {
|
||||
const resKeyPair = await getKeyPair()
|
||||
const parsedData = resKeyPair
|
||||
const userPublicKey = parsedData.publicKey
|
||||
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
|
||||
const uint8PublicKey = Base58.decode(parsedData.publicKey);
|
||||
const keyPair = {
|
||||
privateKey: uint8PrivateKey,
|
||||
publicKey: uint8PublicKey,
|
||||
};
|
||||
const response = await cancelTradeOfferTradeBot({
|
||||
creatorPublicKey: userPublicKey,
|
||||
atAddress: data.atAddress
|
||||
}, keyPair)
|
||||
|
||||
return response
|
||||
|
||||
} else {
|
||||
throw new Error("User declined request");
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(error?.message || "Failed to submit sell order.");
|
||||
}
|
||||
};
|
65
src/transactions/TradeBotCreateRequest.ts
Normal file
65
src/transactions/TradeBotCreateRequest.ts
Normal file
@ -0,0 +1,65 @@
|
||||
// @ts-nocheck
|
||||
|
||||
/**
|
||||
* CrossChain - TradeBot Create Request (Sell Action)
|
||||
*
|
||||
* These are special types of transactions (JSON ENCODED)
|
||||
*/
|
||||
|
||||
export default class TradeBotCreateRequest {
|
||||
constructor() {
|
||||
// ...
|
||||
}
|
||||
|
||||
createTransaction(txnReq) {
|
||||
this.creatorPublicKey(txnReq.creatorPublicKey)
|
||||
this.qortAmount(txnReq.qortAmount)
|
||||
this.fundingQortAmount(txnReq.fundingQortAmount)
|
||||
this.foreignBlockchain(txnReq.foreignBlockchain)
|
||||
this.foreignAmount(txnReq.foreignAmount)
|
||||
this.tradeTimeout(txnReq.tradeTimeout)
|
||||
this.receivingAddress(txnReq.receivingAddress)
|
||||
|
||||
return this.txnRequest()
|
||||
}
|
||||
|
||||
creatorPublicKey(creatorPublicKey) {
|
||||
this._creatorPublicKey = creatorPublicKey
|
||||
}
|
||||
|
||||
qortAmount(qortAmount) {
|
||||
this._qortAmount = qortAmount
|
||||
}
|
||||
|
||||
fundingQortAmount(fundingQortAmount) {
|
||||
this._fundingQortAmount = fundingQortAmount
|
||||
}
|
||||
|
||||
foreignBlockchain(foreignBlockchain) {
|
||||
this._foreignBlockchain = foreignBlockchain
|
||||
}
|
||||
|
||||
foreignAmount(foreignAmount) {
|
||||
this._foreignAmount = foreignAmount
|
||||
}
|
||||
|
||||
tradeTimeout(tradeTimeout) {
|
||||
this._tradeTimeout = tradeTimeout
|
||||
}
|
||||
|
||||
receivingAddress(receivingAddress) {
|
||||
this._receivingAddress = receivingAddress
|
||||
}
|
||||
|
||||
txnRequest() {
|
||||
return {
|
||||
creatorPublicKey: this._creatorPublicKey,
|
||||
qortAmount: this._qortAmount,
|
||||
fundingQortAmount: this._fundingQortAmount,
|
||||
foreignBlockchain: this._foreignBlockchain,
|
||||
foreignAmount: this._foreignAmount,
|
||||
tradeTimeout: this._tradeTimeout,
|
||||
receivingAddress: this._receivingAddress
|
||||
}
|
||||
}
|
||||
}
|
35
src/transactions/TradeBotDeleteRequest.ts
Normal file
35
src/transactions/TradeBotDeleteRequest.ts
Normal file
@ -0,0 +1,35 @@
|
||||
// @ts-nocheck
|
||||
|
||||
/**
|
||||
* CrossChain - DELETE TradeOffer
|
||||
*
|
||||
* These are special types of transactions (JSON ENCODED)
|
||||
*/
|
||||
|
||||
export default class DeleteTradeOffer {
|
||||
constructor() {
|
||||
// ...
|
||||
}
|
||||
|
||||
createTransaction(txnReq) {
|
||||
this.creatorPublicKey(txnReq.creatorPublicKey)
|
||||
this.atAddress(txnReq.atAddress)
|
||||
|
||||
return this.txnRequest()
|
||||
}
|
||||
|
||||
creatorPublicKey(creatorPublicKey) {
|
||||
this._creatorPublicKey = creatorPublicKey
|
||||
}
|
||||
|
||||
atAddress(atAddress) {
|
||||
this._atAddress = atAddress
|
||||
}
|
||||
|
||||
txnRequest() {
|
||||
return {
|
||||
creatorPublicKey: this._creatorPublicKey,
|
||||
atAddress: this._atAddress
|
||||
}
|
||||
}
|
||||
}
|
30
src/transactions/signTradeBotTransaction.ts
Normal file
30
src/transactions/signTradeBotTransaction.ts
Normal file
@ -0,0 +1,30 @@
|
||||
// @ts-nocheck
|
||||
|
||||
|
||||
import nacl from '../deps/nacl-fast'
|
||||
import Base58 from '../deps/Base58'
|
||||
import utils from '../utils/utils'
|
||||
|
||||
const signTradeBotTransaction = async (unsignedTxn, keyPair) => {
|
||||
if (!unsignedTxn) {
|
||||
throw new Error('Unsigned Transaction Bytes not defined')
|
||||
}
|
||||
|
||||
if (!keyPair) {
|
||||
throw new Error('keyPair not defined')
|
||||
}
|
||||
|
||||
const txnBuffer = Base58.decode(unsignedTxn)
|
||||
|
||||
if (keyPair.privateKey.length === undefined) {
|
||||
const _privateKey = Object.keys(keyPair.privateKey).map(function (key) { return keyPair.privateKey[key] })
|
||||
const privateKey = new Uint8Array(_privateKey)
|
||||
const signature = nacl.sign.detached(txnBuffer, privateKey)
|
||||
return utils.appendBuffer(txnBuffer, signature)
|
||||
} else {
|
||||
const signature = nacl.sign.detached(txnBuffer, keyPair.privateKey)
|
||||
return utils.appendBuffer(txnBuffer, signature)
|
||||
}
|
||||
}
|
||||
|
||||
export default signTradeBotTransaction
|
Loading…
x
Reference in New Issue
Block a user