From abe7be473deae6ee9464f46bd8a5520be3dfc5bd Mon Sep 17 00:00:00 2001 From: Phillip Date: Fri, 24 Feb 2023 13:02:05 +0000 Subject: [PATCH 1/3] fix issues --- .../api/transactions/DeployAtTransaction.js | 4 +- .../plugins/core/qdn/browser/browser.src.js | 132 ++++++++++++------ 2 files changed, 89 insertions(+), 47 deletions(-) diff --git a/qortal-ui-crypto/api/transactions/DeployAtTransaction.js b/qortal-ui-crypto/api/transactions/DeployAtTransaction.js index c3eb20e4..a9b3ad5f 100644 --- a/qortal-ui-crypto/api/transactions/DeployAtTransaction.js +++ b/qortal-ui-crypto/api/transactions/DeployAtTransaction.js @@ -1,5 +1,6 @@ 'use strict' import TransactionBase from './TransactionBase.js' +import { store } from '../../api.js' export default class DeployAtTransaction extends TransactionBase { constructor() { @@ -33,7 +34,7 @@ export default class DeployAtTransaction extends TransactionBase { this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) } set rAmount(rAmount) { - this._rAmount = rAmount + this._rAmount = Math.round(rAmount * store.getState().config.coin.decimals) this._rAmountBytes = this.constructor.utils.int64ToBytes(this._rAmount) } @@ -60,7 +61,6 @@ export default class DeployAtTransaction extends TransactionBase { } set rCreationBytes(rCreationBytes) { const decode = this.constructor.Base58.decode(rCreationBytes) - console.log({decode}) this._rCreationBytes = this.constructor.utils.stringtoUTF8Array(decode) this._rCreationBytesLength = this.constructor.utils.int32ToBytes(this._rCreationBytes.length) } diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js index 443d2d00..2ae43c96 100644 --- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js +++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js @@ -231,7 +231,6 @@ class WebBrowser extends LitElement { } render() { - console.log(1, "browser page here"); return html`
@@ -295,7 +294,20 @@ class WebBrowser extends LitElement { } const data = await response.json() - const joinFee = data + const joinFee = (Number(data) / 1e8).toFixed(8) + return joinFee + } + async sendQortFee() { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port + const url = `${nodeUrl}/transactions/unitfee?txType=PAYMENT` + const response = await fetch(url) + if (!response.ok) { + throw new Error('Error when fetching join fee'); + } + + const data = await response.json() + const joinFee = (Number(data) / 1e8).toFixed(8) return joinFee } @@ -452,10 +464,8 @@ class WebBrowser extends LitElement { let response = '{"error": "Request could not be fulfilled"}'; let data = event.data; - console.log('UI received event: ' + JSON.stringify(data)); switch (data.action) { - case 'GET_USER_ACCOUNT': case actions.GET_USER_ACCOUNT: const res1 = await showModalAndWait( actions.GET_USER_ACCOUNT @@ -469,12 +479,12 @@ class WebBrowser extends LitElement { break; } else { const data = {}; - const errorMsg = get('browserpage.bchange17'); + const errorMsg = "User declined to share account details" data['error'] = errorMsg; response = JSON.stringify(data); break; } - case 'LINK_TO_QDN_RESOURCE': + case actions.LINK_TO_QDN_RESOURCE: case actions.QDN_RESOURCE_DISPLAYED: // Links are handled by the core, but the UI also listens for these actions in order to update the address bar. // Note: don't update this.url here, as we don't want to force reload the iframe each time. @@ -566,11 +576,11 @@ class WebBrowser extends LitElement { } - case 'SEND_CHAT_MESSAGE': { + case actions.SEND_CHAT_MESSAGE: { const message = data.message; const recipient = data.destinationAddress; const sendMessage = async (messageText, chatReference) => { - this.loader.show(); + let _reference = new Uint8Array(64); window.crypto.getRandomValues(_reference); let reference = window.parent.Base58.encode(_reference); @@ -623,13 +633,13 @@ class WebBrowser extends LitElement { const getSendChatResponse = (res) => { if (res === true) { - let successString = get("browserpage.bchange23"); - parentEpml.request('showSnackBar', `${successString}`); + return res } else if (res.error) { - parentEpml.request('showSnackBar', res.message); + throw new Error(res.message); + } else { + throw new Error('ERROR: Could not send message'); } - this.loader.hide(); - return res; + }; const chatResponse = await sendMessageRequest(); @@ -665,7 +675,7 @@ class WebBrowser extends LitElement { return } - this.loader.show(); + const tiptapJson = { type: 'doc', @@ -699,14 +709,15 @@ class WebBrowser extends LitElement { // this.sendMessage(stringifyMessageObject, typeMessage); // } try { + this.loader.show(); const msgResponse = await sendMessage(stringifyMessageObject); response = msgResponse; } catch (error) { console.error(error); - return '{"error": "Request could not be fulfilled"}'; + response = '{"error": "Request could not be fulfilled"}'; } finally { this.loader.hide(); - console.log("Case completed."); + } } else { @@ -820,7 +831,7 @@ class WebBrowser extends LitElement { // } - case 'GET_WALLET_BALANCE': { + case actions.GET_WALLET_BALANCE: { const requiredFields = ['coin']; const missingFields = []; @@ -931,23 +942,43 @@ class WebBrowser extends LitElement { } - case 'SEND_COIN': + case actions.SEND_COIN: { + const requiredFields = ['coin', 'destinationAddress', 'amount']; + const missingFields = []; + + requiredFields.forEach((field) => { + if (!data[field]) { + missingFields.push(field); + } + }); + + if (missingFields.length > 0) { + this.loader.hide(); + const missingFieldsString = missingFields.join(', '); + const errorMsg = `Missing fields: ${missingFieldsString}` + let data = {}; + data['error'] = errorMsg; + response = JSON.stringify(data); + break + } // Params: data.coin, data.destinationAddress, data.amount, data.fee // TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction // then set the response string from the core to the `response` variable (defined above) // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}` - const amount = data.amount + const amount = Number(data.amount) let recipient = data.destinationAddress; - const fee = data.fee this.loader.show(); const walletBalance = await parentEpml.request('apiCall', { url: `/addresses/balance/${this.myAddress.address}?apiKey=${this.getApiKey()}`, }) if (isNaN(Number(walletBalance))) { - let snack4string = get("chatpage.cchange48") - parentEpml.request('showSnackBar', `${snack4string}`) - return; + this.loader.hide(); + let errorMsg = "Failed to Fetch QORT Balance. Try again!" + let obj = {}; + obj['error'] = errorMsg; + response = JSON.stringify(obj); + break; } const myRef = await parentEpml.request("apiCall", { @@ -955,27 +986,35 @@ class WebBrowser extends LitElement { url: `/addresses/lastreference/${this.myAddress.address}`, }) - const walletBalanceDecimals = parseFloat(walletBalance) * QORT_DECIMALS; - - if (parseFloat(amount) + parseFloat(data.fee) > parseFloat(walletBalanceDecimals)) { + const walletBalanceDecimals = Number(walletBalance) * QORT_DECIMALS; + const amountDecimals = Number(amount) * QORT_DECIMALS + const fee = await this.sendQortFee() + // TODO fee + if (amountDecimals + (fee * QORT_DECIMALS) > walletBalanceDecimals) { this.loader.hide(); - let snack1string = get("chatpage.cchange51"); - parentEpml.request('showSnackBar', `${snack1string}`); - return false; + let errorMsg = "Insufficient Funds!" + let obj = {}; + obj['error'] = errorMsg; + response = JSON.stringify(obj); + break; } - if (parseFloat(amount) <= 0) { + if (amount <= 0) { this.loader.hide(); - let snack2string = get("chatpage.cchange52"); - parentEpml.request('showSnackBar', `${snack2string}`); - return false; + let errorMsg = "Invalid Amount!" + let obj = {}; + obj['error'] = errorMsg; + response = JSON.stringify(obj); + break; } if (recipient.length === 0) { this.loader.hide(); - let snack3string = get("chatpage.cchange53"); - parentEpml.request('showSnackBar', `${snack3string}`); - return false; + let errorMsg = "Receiver cannot be empty!" + let obj = {}; + obj['error'] = errorMsg; + response = JSON.stringify(obj); + break; } const validateName = async (receiverName) => { @@ -1020,9 +1059,10 @@ class WebBrowser extends LitElement { const res = getTxnRequestResponse(myTransaction) return res; } else { - console.error(`${translate("chatpage.cchange54")}`) - parentEpml.request('showSnackBar', `${translate("chatpage.cchange54")}`) - this.loader.hide(); + + let errorMsg = "Invalid Receiver!" + throw new Error(errorMsg) + } } } @@ -1073,14 +1113,15 @@ class WebBrowser extends LitElement { const getTxnRequestResponse = (txnResponse) => { if (txnResponse.success === false && txnResponse.message) { this.loader.hide(); - throw new Error(txnResponse); + throw new Error(txnResponse.message); } else if (txnResponse.success === true && !txnResponse.data.error) { this.loader.hide(); + return txnResponse.data; } else { this.loader.hide(); - throw new Error(txnResponse); + throw new Error('Error: could not send coin'); } - return txnResponse; + } try { @@ -1088,11 +1129,13 @@ class WebBrowser extends LitElement { response = result; } catch (error) { console.error(error); - return '{"error": "Request could not be fulfilled"}'; + response = '{"error": "Request could not be fulfilled"}'; } finally { - console.log("Case completed."); + this.loader.hide(); } break; + } + default: console.log('Unhandled message: ' + JSON.stringify(data)); @@ -1107,7 +1150,6 @@ class WebBrowser extends LitElement { // Not all responses will be JSON responseObj = response; } - // Respond to app if (responseObj.error != null) { event.ports[0].postMessage({ From f08fb36fdcbd472b836ba14953c029641bf37bf5 Mon Sep 17 00:00:00 2001 From: Phillip Date: Fri, 24 Feb 2023 13:14:02 +0000 Subject: [PATCH 2/3] add translations --- qortal-ui-core/language/us.json | 4 +++- qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index e0892920..be5010f8 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -500,7 +500,9 @@ "bchange20": "Do you give this application permission to get your wallet balance?", "bchange21": "Fetch Wallet Failed. Please try again!", "bchange22": "Do you give this application permission to send a chat message?", - "bchange23": "Message Sent!" + "bchange23": "Message Sent!", + "bchange24": "Reject", + "bchange25": "Accept" }, "datapage": { "dchange1": "Data Management", diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js index 2ae43c96..5a423b8f 100644 --- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js +++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js @@ -1487,8 +1487,8 @@ async function showModalAndWait(type, data) { ${type === actions.SEND_CHAT_MESSAGE ? `` : ''}
From 8f9498b4c9b7c7a63f9bbff5bf54ec05c84787b9 Mon Sep 17 00:00:00 2001 From: Phillip Date: Fri, 24 Feb 2023 14:56:52 +0000 Subject: [PATCH 3/3] version 2 api transaction for q-app --- qortal-ui-core/src/plugins/routes.js | 60 ++++++++++++++++--- qortal-ui-crypto/api/api.js | 2 +- qortal-ui-crypto/api/createTransaction.js | 6 ++ .../plugins/core/qdn/browser/browser.src.js | 11 +++- .../plugins/utils/publish-image.js | 4 +- 5 files changed, 71 insertions(+), 12 deletions(-) diff --git a/qortal-ui-core/src/plugins/routes.js b/qortal-ui-core/src/plugins/routes.js index f51001f8..ac83416b 100644 --- a/qortal-ui-core/src/plugins/routes.js +++ b/qortal-ui-core/src/plugins/routes.js @@ -22,6 +22,7 @@ import framePasteMenu from '../functional-components/frame-paste-menu.js'; const createTransaction = api.createTransaction; const processTransaction = api.processTransaction; +const processTransactionVersion2 = api.processTransactionVersion2; const signChatTransaction = api.signChatTransaction; const signArbitraryTransaction = api.signArbitraryTransaction; const tradeBotCreateRequest = api.tradeBotCreateRequest; @@ -144,8 +145,16 @@ export const routes = { if (!req.disableModal && !req.data.disableModal) { await requestTransactionDialog.requestTransaction(tx); } - - const res = await processTransaction(tx.signedBytes); + + let res + + if(req.data.apiVersion && req.data.apiVersion === 2){ + res = await processTransactionVersion2(tx.signedBytes) + } + if(!req.data.apiVersion){ + res = await processTransaction(tx.signedBytes); + } + let extraData = {} if(req.data.type === 38 && tx && tx._rewardShareKeyPair && tx._rewardShareKeyPair.secretKey){ extraData.rewardSharePrivateKey = Base58.encode(tx._rewardShareKeyPair.secretKey) @@ -191,7 +200,16 @@ export const routes = { _keyPair, req.data.params ); - const res = await processTransaction(tx.signedBytes); + let res + + if(req.data.apiVersion && req.data.apiVersion === 2){ + res = await processTransactionVersion2(tx.signedBytes) + } + if(!req.data.apiVersion){ + res = await processTransaction(tx.signedBytes); + } + + response = { success: true, data: res, @@ -242,8 +260,16 @@ export const routes = { req.data.chatNonce, store.getState().app.wallet._addresses[req.data.nonce].keyPair ); + + let res - const res = await processTransaction(signedChatBytes); + if(req.data.apiVersion && req.data.apiVersion === 2){ + res = await processTransactionVersion2(signedChatBytes) + } + if(!req.data.apiVersion){ + res = await processTransaction(signedChatBytes); + } + response = res; } catch (e) { console.error(e); @@ -262,8 +288,15 @@ export const routes = { req.data.arbitraryNonce, store.getState().app.wallet._addresses[req.data.nonce].keyPair ); + let res - const res = await processTransaction(signedArbitraryBytes); + if(req.data.apiVersion && req.data.apiVersion === 2){ + res = await processTransactionVersion2(signedArbitraryBytes) + } + if(!req.data.apiVersion){ + res = await processTransaction(signedArbitraryBytes); + } + response = res; } catch (e) { console.error(e); @@ -293,8 +326,14 @@ export const routes = { unsignedTxn, store.getState().app.selectedAddress.keyPair ); + let res - const res = await processTransaction(signedTxnBytes); + if(req.data.apiVersion && req.data.apiVersion === 2){ + res = await processTransactionVersion2(signedTxnBytes) + } + if(!req.data.apiVersion){ + res = await processTransaction(signedTxnBytes); + } response = res; } catch (e) { console.error(e); @@ -327,8 +366,15 @@ export const routes = { unsignedTxn, store.getState().app.selectedAddress.keyPair ); + + let res - const res = await processTransaction(signedTxnBytes); + if(req.data.apiVersion && req.data.apiVersion === 2){ + res = await processTransactionVersion2(signedTxnBytes) + } + if(!req.data.apiVersion){ + res = await processTransaction(signedTxnBytes); + } response = res; } catch (e) { diff --git a/qortal-ui-crypto/api/api.js b/qortal-ui-crypto/api/api.js index 98da919b..e8e156dd 100644 --- a/qortal-ui-crypto/api/api.js +++ b/qortal-ui-crypto/api/api.js @@ -1,5 +1,5 @@ export { request } from './fetch-request.js' export { transactionTypes as transactions } from './transactions/transactions.js' -export { processTransaction, createTransaction, computeChatNonce, signChatTransaction, signArbitraryTransaction } from './createTransaction.js' +export { processTransaction, processTransactionVersion2, createTransaction, computeChatNonce, signChatTransaction, signArbitraryTransaction } from './createTransaction.js' export { tradeBotCreateRequest, tradeBotRespondRequest, signTradeBotTxn, deleteTradeOffer, sendBtc, sendLtc, sendDoge, sendDgb, sendRvn, sendArrr } from './tradeRequest.js' export { cancelAllOffers } from './transactions/trade-portal/tradeoffer/cancelAllOffers.js' diff --git a/qortal-ui-crypto/api/createTransaction.js b/qortal-ui-crypto/api/createTransaction.js index 2a56aa56..169561dd 100644 --- a/qortal-ui-crypto/api/createTransaction.js +++ b/qortal-ui-crypto/api/createTransaction.js @@ -36,3 +36,9 @@ export const processTransaction = bytes => request('/transactions/process', { method: 'POST', body: Base58.encode(bytes) }) + +export const processTransactionVersion2 = bytes => request('/transactions/process?apiVersion=2', { + method: 'POST', + body: Base58.encode(bytes) +}) + diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js index 5a423b8f..8f695dbf 100644 --- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js +++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js @@ -342,7 +342,8 @@ class WebBrowser extends LitElement { lastReference: lastRef, groupdialog1: groupdialog1, groupdialog2: groupdialog2 - } + }, + apiVersion: 2 }) return myTxnrequest } @@ -398,7 +399,8 @@ class WebBrowser extends LitElement { lastReference: lastRef, atDeployDialog1: groupdialog1, atDeployDialog2: groupdialog2 - } + }, + apiVersion: 2 }) return myTxnrequest } @@ -550,6 +552,7 @@ class WebBrowser extends LitElement { selectedAddress: this.selectedAddress, worker: worker, isBase64: true, + apiVersion: 2 }); response = JSON.stringify(resPublish); @@ -624,7 +627,8 @@ class WebBrowser extends LitElement { let _response = await parentEpml.request('sign_chat', { nonce: this.selectedAddress.nonce, chatBytesArray: chatBytesArray, - chatNonce: nonce + chatNonce: nonce, + apiVersion: 2 }); const chatResponse = getSendChatResponse(_response); @@ -1106,6 +1110,7 @@ class WebBrowser extends LitElement { dialogAddress, dialogName }, + apiVersion: 2 }) return myTxnrequest; } diff --git a/qortal-ui-plugins/plugins/utils/publish-image.js b/qortal-ui-plugins/plugins/utils/publish-image.js index 56668e23..11aed013 100644 --- a/qortal-ui-plugins/plugins/utils/publish-image.js +++ b/qortal-ui-plugins/plugins/utils/publish-image.js @@ -18,7 +18,8 @@ export const publishData = async ({ selectedAddress, worker, isBase64, - metaData + metaData, + apiVersion }) => { const validateName = async (receiverName) => { let nameRes = await parentEpml.request("apiCall", { @@ -71,6 +72,7 @@ export const publishData = async ({ arbitraryBytesBase58: transactionBytesBase58, arbitraryBytesForSigningBase58: convertedBytesBase58, arbitraryNonce: nonce, + apiVersion: apiVersion ? apiVersion : null }) let myResponse = { error: "" } if (response === false) {