From edc7dae13dd234edca1762480cbdd41a3e180ae3 Mon Sep 17 00:00:00 2001 From: Phillip Date: Thu, 16 Mar 2023 13:53:12 +0000 Subject: [PATCH] publish option with fee --- qortal-ui-core/language/us.json | 3 +- qortal-ui-core/src/plugins/routes.js | 27 +++++++++++ qortal-ui-crypto/api/api.js | 2 +- qortal-ui-crypto/api/createTransaction.js | 7 +++ .../arbitrary/signArbitraryWithFee.js | 33 +++++++++++++ .../plugins/core/qdn/browser/browser.src.js | 18 +++++++- .../plugins/utils/publish-image.js | 46 +++++++++++++++++-- 7 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 qortal-ui-crypto/api/transactions/arbitrary/signArbitraryWithFee.js diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index 034d786d..8db1812a 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -581,7 +581,8 @@ "bchange25": "No sensitive data is shared.", "bchange26": "Always authenticate automatically", "bchange27": "Reject", - "bchange28": "Accept" + "bchange28": "Accept", + "bchange29": "Instant publish (requires 0.001 QORT fee)" }, "datapage": { "dchange1": "Data Management", diff --git a/qortal-ui-core/src/plugins/routes.js b/qortal-ui-core/src/plugins/routes.js index ac83416b..4e81f894 100644 --- a/qortal-ui-core/src/plugins/routes.js +++ b/qortal-ui-core/src/plugins/routes.js @@ -25,6 +25,7 @@ const processTransaction = api.processTransaction; const processTransactionVersion2 = api.processTransactionVersion2; const signChatTransaction = api.signChatTransaction; const signArbitraryTransaction = api.signArbitraryTransaction; +const signArbitraryWithFeeTransaction = api.signArbitraryWithFeeTransaction; const tradeBotCreateRequest = api.tradeBotCreateRequest; const tradeBotRespondRequest = api.tradeBotRespondRequest; const signTradeBotTxn = api.signTradeBotTxn; @@ -306,6 +307,32 @@ export const routes = { return response; }, + sign_arbitrary_with_fee: async (req) => { + let response; + try { + const signedArbitraryBytes = await signArbitraryWithFeeTransaction( + req.data.arbitraryBytesBase58, + req.data.arbitraryBytesForSigningBase58, + store.getState().app.wallet._addresses[req.data.nonce].keyPair + ); + let res + + 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); + console.error(e.message); + response = false; + } + return response; + }, + showNotification: async (req) => { doNewMessage(req.data); }, diff --git a/qortal-ui-crypto/api/api.js b/qortal-ui-crypto/api/api.js index e8e156dd..36a635cc 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, processTransactionVersion2, createTransaction, computeChatNonce, signChatTransaction, signArbitraryTransaction } from './createTransaction.js' +export { processTransaction, processTransactionVersion2, createTransaction, computeChatNonce, signChatTransaction, signArbitraryTransaction, signArbitraryWithFeeTransaction } 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 169561dd..b4bf7802 100644 --- a/qortal-ui-crypto/api/createTransaction.js +++ b/qortal-ui-crypto/api/createTransaction.js @@ -3,6 +3,7 @@ import Base58 from './deps/Base58.js' import { request } from './fetch-request' import signChat from './transactions/chat/signChat.js' import signArbitrary from './transactions/arbitrary/signArbitrary.js' +import signArbitraryWithFee from './transactions/arbitrary/signArbitraryWithFee.js' export const createTransaction = (type, keyPair, params) => { @@ -31,6 +32,12 @@ export const signArbitraryTransaction = (arbitraryBytesBase58, arbitraryBytesFor return signArbitrary(arbitraryBytesBase58, arbitraryBytesForSigningBase58, nonce, keyPair) } +export const signArbitraryWithFeeTransaction = (arbitraryBytesBase58, arbitraryBytesForSigningBase58, keyPair) => { + return signArbitraryWithFee(arbitraryBytesBase58, arbitraryBytesForSigningBase58, keyPair) +} + + + // Process Transactions export const processTransaction = bytes => request('/transactions/process', { method: 'POST', diff --git a/qortal-ui-crypto/api/transactions/arbitrary/signArbitraryWithFee.js b/qortal-ui-crypto/api/transactions/arbitrary/signArbitraryWithFee.js new file mode 100644 index 00000000..1a71cc2e --- /dev/null +++ b/qortal-ui-crypto/api/transactions/arbitrary/signArbitraryWithFee.js @@ -0,0 +1,33 @@ +import nacl from '../../deps/nacl-fast.js' +import utils from '../../deps/utils.js' +import Base58 from '../../deps/Base58.js' + +const signArbitraryWithFee = (arbitraryBytesBase58, arbitraryBytesForSigningBase58, keyPair) => { + + if (!arbitraryBytesBase58) { + throw new Error('ArbitraryBytesBase58 not defined') + } + + + if (!keyPair) { + throw new Error('keyPair not defined') + } + + const arbitraryBytes = Base58.decode(arbitraryBytesBase58) + const _arbitraryBytesBuffer = Object.keys(arbitraryBytes).map(function (key) { return arbitraryBytes[key]; }) + const arbitraryBytesBuffer = new Uint8Array(_arbitraryBytesBuffer) + + const arbitraryBytesForSigning = Base58.decode(arbitraryBytesForSigningBase58) + const _arbitraryBytesForSigningBuffer = Object.keys(arbitraryBytesForSigning).map(function (key) { return arbitraryBytesForSigning[key]; }) + const arbitraryBytesForSigningBuffer = new Uint8Array(_arbitraryBytesForSigningBuffer) + + + + const signature = nacl.sign.detached(arbitraryBytesForSigningBuffer, keyPair.privateKey) + + const signedBytes = utils.appendBuffer(arbitraryBytesBuffer, signature) + + return signedBytes +} + +export default signArbitraryWithFee 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 420d995e..27c706ca 100644 --- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js +++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js @@ -564,7 +564,8 @@ class WebBrowser extends LitElement { selectedAddress: this.selectedAddress, worker: worker, isBase64: true, - apiVersion: 2 + apiVersion: 2, + withFee: res2.userData.isWithFee === true ? true: false }); response = JSON.stringify(resPublish); @@ -1556,7 +1557,16 @@ async function showModalAndWait(type, data) { ` : ''} - ${type === actions.PUBLISH_QDN_RESOURCE ? `` : ''} + ${type === actions.PUBLISH_QDN_RESOURCE ? `` : ''} ${type === actions.GET_WALLET_BALANCE ? `` : ''} ${type === actions.SEND_CHAT_MESSAGE ? `` : ''} @@ -1573,6 +1583,10 @@ async function showModalAndWait(type, data) { const okButton = modal.querySelector('#ok-button'); okButton.addEventListener('click', () => { const userData = {}; + if (type === actions.PUBLISH_QDN_RESOURCE) { + const isWithFeeCheckbox = modal.querySelector('#isWithFee'); + userData.isWithFee = isWithFeeCheckbox.checked; + } if (modal.parentNode === document.body) { document.body.removeChild(modal); } diff --git a/qortal-ui-plugins/plugins/utils/publish-image.js b/qortal-ui-plugins/plugins/utils/publish-image.js index 11aed013..22484335 100644 --- a/qortal-ui-plugins/plugins/utils/publish-image.js +++ b/qortal-ui-plugins/plugins/utils/publish-image.js @@ -19,7 +19,8 @@ export const publishData = async ({ worker, isBase64, metaData, - apiVersion + apiVersion, + withFee }) => { const validateName = async (receiverName) => { let nameRes = await parentEpml.request("apiCall", { @@ -81,6 +82,33 @@ export const publishData = async ({ myResponse = response } + return myResponse + } + + const signAndProcessWithFee = async (transactionBytesBase58) => { + let convertedBytesBase58 = await convertBytesForSigning( + transactionBytesBase58 + ) + if (convertedBytesBase58.error) { + throw new Error('Error when signing'); + } + + + + + let response = await parentEpml.request("sign_arbitrary_with_fee", { + nonce: selectedAddress.nonce, + arbitraryBytesBase58: transactionBytesBase58, + arbitraryBytesForSigningBase58: convertedBytesBase58, + apiVersion: apiVersion ? apiVersion : null + }) + let myResponse = { error: "" } + if (response === false) { + throw new Error('Error when signing'); + } else { + myResponse = response + } + return myResponse } @@ -91,14 +119,22 @@ export const publishData = async ({ } let transactionBytes = await uploadData(registeredName, path, file) if (transactionBytes.error) { - throw new Error('Error when uploading'); + throw new Error(transactionBytes.message || 'Error when uploading'); } else if ( transactionBytes.includes("Error 500 Internal Server Error") ) { throw new Error('Error when uploading'); } - let signAndProcessRes = await signAndProcess(transactionBytes) + let signAndProcessRes + if(withFee){ + signAndProcessRes = await signAndProcessWithFee(transactionBytes) + + } + if(!withFee){ + signAndProcessRes = await signAndProcess(transactionBytes) + + } if (signAndProcessRes.error) { throw new Error('Error when signing'); } @@ -139,6 +175,10 @@ export const publishData = async ({ } } + + if(withFee){ + uploadDataUrl = uploadDataUrl + '&fee=100000' + } let uploadDataRes = await parentEpml.request("apiCall", { type: "api",