mirror of
https://github.com/Qortal/qortal-mobile.git
synced 2025-04-01 18:15:54 +00:00
added sign tx qortalrequest
This commit is contained in:
parent
de3933b04b
commit
1040fd4018
12
package-lock.json
generated
12
package-lock.json
generated
@ -68,6 +68,7 @@
|
|||||||
"react-frame-component": "^5.2.7",
|
"react-frame-component": "^5.2.7",
|
||||||
"react-infinite-scroller": "^1.2.6",
|
"react-infinite-scroller": "^1.2.6",
|
||||||
"react-intersection-observer": "^9.13.0",
|
"react-intersection-observer": "^9.13.0",
|
||||||
|
"react-json-view-lite": "^2.0.1",
|
||||||
"react-loader-spinner": "^6.1.6",
|
"react-loader-spinner": "^6.1.6",
|
||||||
"react-qr-code": "^2.0.15",
|
"react-qr-code": "^2.0.15",
|
||||||
"react-quick-pinch-zoom": "^5.1.0",
|
"react-quick-pinch-zoom": "^5.1.0",
|
||||||
@ -11999,6 +12000,17 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/react-json-view-lite": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-4JdlXC+dWPRXPL4fK/NsK6W103+mmpXDeWCHJGhgjPSvuyHnpwQUJ+ClUj4MFlLb4cPxi3T0/PW414JlTKMCJg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-lifecycles-compat": {
|
"node_modules/react-lifecycles-compat": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||||
|
@ -87,7 +87,8 @@
|
|||||||
"tiptap-extension-resize-image": "^1.1.8",
|
"tiptap-extension-resize-image": "^1.1.8",
|
||||||
"ts-key-enum": "^2.0.12",
|
"ts-key-enum": "^2.0.12",
|
||||||
"vite-plugin-top-level-await": "^1.4.4",
|
"vite-plugin-top-level-await": "^1.4.4",
|
||||||
"vite-plugin-wasm": "^3.3.0"
|
"vite-plugin-wasm": "^3.3.0",
|
||||||
|
"react-json-view-lite": "^2.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/dom": "^10.3.0",
|
"@testing-library/dom": "^10.3.0",
|
||||||
|
10
src/App.tsx
10
src/App.tsx
@ -27,6 +27,8 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { decryptStoredWallet } from "./utils/decryptWallet";
|
import { decryptStoredWallet } from "./utils/decryptWallet";
|
||||||
|
import { JsonView, allExpanded, darkStyles } from 'react-json-view-lite';
|
||||||
|
import 'react-json-view-lite/dist/index.css';
|
||||||
import { CountdownCircleTimer } from "react-countdown-circle-timer";
|
import { CountdownCircleTimer } from "react-countdown-circle-timer";
|
||||||
import Logo1 from "./assets/svgs/Logo1.svg";
|
import Logo1 from "./assets/svgs/Logo1.svg";
|
||||||
import Logo1Dark from "./assets/svgs/Logo1Dark.svg";
|
import Logo1Dark from "./assets/svgs/Logo1Dark.svg";
|
||||||
@ -3163,7 +3165,15 @@ await showInfo({
|
|||||||
>
|
>
|
||||||
{messageQortalRequestExtension?.highlightedText}
|
{messageQortalRequestExtension?.highlightedText}
|
||||||
</TextP>
|
</TextP>
|
||||||
|
{messageQortalRequestExtension?.json && (
|
||||||
|
<>
|
||||||
|
<Spacer height="15px" />
|
||||||
|
|
||||||
|
<JsonView data={messageQortalRequestExtension?.json} shouldExpandNode={allExpanded} style={darkStyles} />
|
||||||
|
<Spacer height="15px" />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{messageQortalRequestExtension?.fee && (
|
{messageQortalRequestExtension?.fee && (
|
||||||
<>
|
<>
|
||||||
<Spacer height="15px" />
|
<Spacer height="15px" />
|
||||||
|
@ -183,7 +183,7 @@ const UIQortalRequests = [
|
|||||||
'GET_TX_ACTIVITY_SUMMARY', 'GET_FOREIGN_FEE', 'UPDATE_FOREIGN_FEE',
|
'GET_TX_ACTIVITY_SUMMARY', 'GET_FOREIGN_FEE', 'UPDATE_FOREIGN_FEE',
|
||||||
'GET_SERVER_CONNECTION_HISTORY', 'SET_CURRENT_FOREIGN_SERVER',
|
'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', 'ADMIN_ACTION', 'OPEN_NEW_TAB', 'CREATE_AND_COPY_EMBED_LINK', 'DECRYPT_QORTAL_GROUP_DATA', 'DECRYPT_DATA_WITH_SHARING_KEY', 'DELETE_HOSTED_DATA', 'GET_HOSTED_DATA'
|
'CREATE_TRADE_SELL_ORDER', 'CANCEL_TRADE_SELL_ORDER', 'IS_USING_GATEWAY', 'SIGN_TRANSACTION', 'ADMIN_ACTION', 'OPEN_NEW_TAB', 'CREATE_AND_COPY_EMBED_LINK', 'DECRYPT_QORTAL_GROUP_DATA', 'DECRYPT_DATA_WITH_SHARING_KEY', 'DELETE_HOSTED_DATA', 'GET_HOSTED_DATA'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { gateways, getApiKeyFromStorage } from "./background";
|
import { gateways, getApiKeyFromStorage } from "./background";
|
||||||
import { addForeignServer, addListItems, adminAction, cancelSellOrder, createAndCopyEmbedLink, createBuyOrder, createPoll, decryptData, decryptDataWithSharingKey, decryptQortalGroupData, deleteHostedData, deleteListItems, deployAt, encryptData, encryptDataWithSharingKey, encryptQortalGroupData, getCrossChainServerInfo, getDaySummary, getForeignFee, getHostedData, getListItems, getServerConnectionHistory, getTxActivitySummary, getUserAccount, getUserWallet, getUserWalletInfo, getWalletBalance, joinGroup, openNewTab, publishMultipleQDNResources, publishQDNResource, removeForeignServer, saveFile, sendChatMessage, sendCoin, setCurrentForeignServer, updateForeignFee, voteOnPoll } from "./qortalRequests/get";
|
import { addForeignServer, addListItems, adminAction, cancelSellOrder, createAndCopyEmbedLink, createBuyOrder, createPoll, decryptData, decryptDataWithSharingKey, decryptQortalGroupData, deleteHostedData, deleteListItems, deployAt, encryptData, encryptDataWithSharingKey, encryptQortalGroupData, getCrossChainServerInfo, getDaySummary, getForeignFee, getHostedData, getListItems, getServerConnectionHistory, getTxActivitySummary, getUserAccount, getUserWallet, getUserWalletInfo, getWalletBalance, joinGroup, openNewTab, publishMultipleQDNResources, publishQDNResource, removeForeignServer, saveFile, sendChatMessage, sendCoin, setCurrentForeignServer, signTransaction, updateForeignFee, voteOnPoll } from "./qortalRequests/get";
|
||||||
import { getData, storeData } from "./utils/chromeStorage";
|
import { getData, storeData } from "./utils/chromeStorage";
|
||||||
|
|
||||||
|
|
||||||
@ -674,6 +674,25 @@ export const isRunningGateway = async ()=> {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "SIGN_TRANSACTION": {
|
||||||
|
try {
|
||||||
|
const res = await signTransaction(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 "OPEN_NEW_TAB": {
|
case "OPEN_NEW_TAB": {
|
||||||
try {
|
try {
|
||||||
|
@ -45,6 +45,8 @@ import { executeEvent } from "../utils/events";
|
|||||||
import { extractComponents } from "../components/Chat/MessageDisplay";
|
import { extractComponents } from "../components/Chat/MessageDisplay";
|
||||||
import { decryptResource, getGroupAdmins, getPublishesFromAdmins, validateSecretKey } from "../components/Group/Group";
|
import { decryptResource, getGroupAdmins, getPublishesFromAdmins, validateSecretKey } from "../components/Group/Group";
|
||||||
import { getPublishesFromAdminsAdminSpace } from "../components/Chat/AdminSpaceInner";
|
import { getPublishesFromAdminsAdminSpace } from "../components/Chat/AdminSpaceInner";
|
||||||
|
import nacl from "../deps/nacl-fast";
|
||||||
|
import utils from "../utils/utils";
|
||||||
|
|
||||||
const btcFeePerByte = 0.00000100
|
const btcFeePerByte = 0.00000100
|
||||||
const ltcFeePerByte = 0.00000030
|
const ltcFeePerByte = 0.00000030
|
||||||
@ -3210,6 +3212,98 @@ export const adminAction = async (data, isFromExtension) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const signTransaction = async (data, isFromExtension) => {
|
||||||
|
const requiredFields = ["unsignedBytes"];
|
||||||
|
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 shouldProcess = data?.process || false;
|
||||||
|
const _url = await createEndpoint(
|
||||||
|
"/transactions/decode?ignoreValidityChecks=false"
|
||||||
|
);
|
||||||
|
|
||||||
|
const _body = data.unsignedBytes;
|
||||||
|
const response = await fetch(_url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: _body,
|
||||||
|
});
|
||||||
|
if (!response.ok) throw new Error("Failed to decode transaction");
|
||||||
|
const decodedData = await response.json();
|
||||||
|
const resPermission = await getUserPermission(
|
||||||
|
{
|
||||||
|
text1: `Do you give this application permission to ${ shouldProcess ? 'SIGN and PROCESS' : 'SIGN' } a transaction?`,
|
||||||
|
highlightedText: "Read the transaction carefully before accepting!",
|
||||||
|
text2: `Tx type: ${decodedData.type}`,
|
||||||
|
json: decodedData,
|
||||||
|
},
|
||||||
|
isFromExtension
|
||||||
|
);
|
||||||
|
const { accepted } = resPermission;
|
||||||
|
if (accepted) {
|
||||||
|
|
||||||
|
const urlConverted = await createEndpoint("/transactions/convert");
|
||||||
|
|
||||||
|
const responseConverted = await fetch(urlConverted, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: data.unsignedBytes,
|
||||||
|
});
|
||||||
|
const resKeyPair = await getKeyPair();
|
||||||
|
const parsedData = resKeyPair;
|
||||||
|
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
|
||||||
|
const uint8PublicKey = Base58.decode(parsedData.publicKey);
|
||||||
|
const keyPair = {
|
||||||
|
privateKey: uint8PrivateKey,
|
||||||
|
publicKey: uint8PublicKey,
|
||||||
|
};
|
||||||
|
const convertedBytes = await responseConverted.text();
|
||||||
|
const txBytes = Base58.decode(data.unsignedBytes);
|
||||||
|
const _arbitraryBytesBuffer = Object.keys(txBytes).map(function (key) {
|
||||||
|
return txBytes[key];
|
||||||
|
});
|
||||||
|
const arbitraryBytesBuffer = new Uint8Array(_arbitraryBytesBuffer);
|
||||||
|
const txByteSigned = Base58.decode(convertedBytes);
|
||||||
|
const _bytesForSigningBuffer = Object.keys(txByteSigned).map(function (
|
||||||
|
key
|
||||||
|
) {
|
||||||
|
return txByteSigned[key];
|
||||||
|
});
|
||||||
|
const bytesForSigningBuffer = new Uint8Array(_bytesForSigningBuffer);
|
||||||
|
const signature = nacl.sign.detached(
|
||||||
|
bytesForSigningBuffer,
|
||||||
|
keyPair.privateKey
|
||||||
|
);
|
||||||
|
const signedBytes = utils.appendBuffer(arbitraryBytesBuffer, signature);
|
||||||
|
const signedBytesToBase58 = Base58.encode(signedBytes);
|
||||||
|
if(!shouldProcess){
|
||||||
|
return uint8ArrayToBase64(signedBytes);
|
||||||
|
}
|
||||||
|
const res = await processTransactionVersion2(signedBytesToBase58);
|
||||||
|
if (!res?.signature)
|
||||||
|
throw new Error(
|
||||||
|
res?.message || "Transaction was not able to be processed"
|
||||||
|
);
|
||||||
|
return res;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error("User declined request");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const openNewTab = async (data, isFromExtension) => {
|
export const openNewTab = async (data, isFromExtension) => {
|
||||||
const requiredFields = [
|
const requiredFields = [
|
||||||
"qortalLink",
|
"qortalLink",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user