mirror of
https://github.com/Qortal/chrome-extension.git
synced 2025-03-28 08:15:55 +00:00
commit
6de89494ac
26
package-lock.json
generated
26
package-lock.json
generated
@ -10,6 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.11.4",
|
"@emotion/react": "^11.11.4",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
|
"@mui/icons-material": "^5.16.4",
|
||||||
"@mui/material": "^5.15.14",
|
"@mui/material": "^5.15.14",
|
||||||
"@testing-library/jest-dom": "^6.4.6",
|
"@testing-library/jest-dom": "^6.4.6",
|
||||||
"@testing-library/user-event": "^14.5.2",
|
"@testing-library/user-event": "^14.5.2",
|
||||||
@ -1221,6 +1222,31 @@
|
|||||||
"url": "https://opencollective.com/mui-org"
|
"url": "https://opencollective.com/mui-org"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mui/icons-material": {
|
||||||
|
"version": "5.16.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.4.tgz",
|
||||||
|
"integrity": "sha512-j9/CWctv6TH6Dou2uR2EH7UOgu79CW/YcozxCYVLJ7l03pCsiOlJ5sBArnWJxJ+nGkFwyL/1d1k8JEPMDR125A==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.23.9"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mui-org"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@mui/material": "^5.0.0",
|
||||||
|
"@types/react": "^17.0.0 || ^18.0.0",
|
||||||
|
"react": "^17.0.0 || ^18.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@mui/material": {
|
"node_modules/@mui/material": {
|
||||||
"version": "5.15.14",
|
"version": "5.15.14",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.14.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.15.14.tgz",
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.11.4",
|
"@emotion/react": "^11.11.4",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
|
"@mui/icons-material": "^5.16.4",
|
||||||
"@mui/material": "^5.15.14",
|
"@mui/material": "^5.15.14",
|
||||||
"@testing-library/jest-dom": "^6.4.6",
|
"@testing-library/jest-dom": "^6.4.6",
|
||||||
"@testing-library/user-event": "^14.5.2",
|
"@testing-library/user-event": "^14.5.2",
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
// In your content script
|
// In your content script
|
||||||
document.addEventListener('qortalExtensionRequests', async (event) => {
|
document.addEventListener('qortalExtensionRequests', async (event) => {
|
||||||
const { type, payload, requestId, timeout } = event.detail; // Capture the requestId
|
const { type, payload, requestId, timeout } = event.detail; // Capture the requestId
|
||||||
|
|
||||||
if (type === 'REQUEST_USER_INFO') {
|
if (type === 'REQUEST_USER_INFO') {
|
||||||
const hostname = window.location.hostname
|
const hostname = window.location.hostname
|
||||||
const res = await connection(hostname)
|
const res = await connection(hostname)
|
||||||
@ -92,7 +91,66 @@ document.addEventListener('qortalExtensionRequests', async (event) => {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (type === 'REQUEST_AUTHENTICATION') {
|
} else if (type === 'REQUEST_BUY_ORDER') {
|
||||||
|
const hostname = window.location.hostname
|
||||||
|
const res = await connection(hostname)
|
||||||
|
if(!res){
|
||||||
|
document.dispatchEvent(new CustomEvent('qortalExtensionResponses', {
|
||||||
|
detail: { type: "BUY_ORDER", data: {
|
||||||
|
error: "Not authorized"
|
||||||
|
}, requestId }
|
||||||
|
}));
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.runtime.sendMessage({ action: "buyOrder", payload: {
|
||||||
|
qortalAtAddress: payload.qortalAtAddress,
|
||||||
|
hostname
|
||||||
|
|
||||||
|
}, timeout}, (response) => {
|
||||||
|
if (response.error) {
|
||||||
|
document.dispatchEvent(new CustomEvent('qortalExtensionResponses', {
|
||||||
|
detail: { type: "BUY_ORDER", data: {
|
||||||
|
error: response.error
|
||||||
|
}, requestId }
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
// Include the requestId in the detail when dispatching the response
|
||||||
|
document.dispatchEvent(new CustomEvent('qortalExtensionResponses', {
|
||||||
|
detail: { type: "BUY_ORDER", data: response, requestId }
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if(type === 'REQUEST_LTC_BALANCE'){
|
||||||
|
|
||||||
|
|
||||||
|
const hostname = window.location.hostname
|
||||||
|
const res = await connection(hostname)
|
||||||
|
if(!res){
|
||||||
|
document.dispatchEvent(new CustomEvent('qortalExtensionResponses', {
|
||||||
|
detail: { type: "USER_INFO", data: {
|
||||||
|
error: "Not authorized"
|
||||||
|
}, requestId }
|
||||||
|
}));
|
||||||
|
return
|
||||||
|
}
|
||||||
|
chrome.runtime.sendMessage({ action: "ltcBalance", payload: {
|
||||||
|
hostname
|
||||||
|
}, timeout }, (response) => {
|
||||||
|
if (response.error) {
|
||||||
|
document.dispatchEvent(new CustomEvent('qortalExtensionResponses', {
|
||||||
|
detail: { type: "LTC_BALANCE", data: {
|
||||||
|
error: response.error
|
||||||
|
}, requestId }
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
// Include the requestId in the detail when dispatching the response
|
||||||
|
document.dispatchEvent(new CustomEvent('qortalExtensionResponses', {
|
||||||
|
detail: { type: "LTC_BALANCE", data: response, requestId }
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (type === 'REQUEST_AUTHENTICATION') {
|
||||||
const hostname = window.location.hostname
|
const hostname = window.location.hostname
|
||||||
const res = await connection(hostname)
|
const res = await connection(hostname)
|
||||||
if(!res){
|
if(!res){
|
||||||
@ -187,5 +245,13 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
|
|||||||
type: "LOGOUT",
|
type: "LOGOUT",
|
||||||
from: 'qortal'
|
from: 'qortal'
|
||||||
}, "*");
|
}, "*");
|
||||||
}
|
} else if (message.type === "RESPONSE_FOR_TRADES") {
|
||||||
});
|
// Notify the web page
|
||||||
|
window.postMessage({
|
||||||
|
type: "RESPONSE_FOR_TRADES",
|
||||||
|
from: 'qortal',
|
||||||
|
payload: message.message
|
||||||
|
}, "*");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "Qortal",
|
"name": "Qortal",
|
||||||
"version": "1.0.0",
|
"version": "1.2.0",
|
||||||
"icons": {
|
"icons": {
|
||||||
"16": "qort.png",
|
"16": "qort.png",
|
||||||
"32": "qort.png",
|
"32": "qort.png",
|
||||||
@ -16,10 +16,14 @@
|
|||||||
},
|
},
|
||||||
"permissions": [ "storage", "system.display", "activeTab", "tabs"
|
"permissions": [ "storage", "system.display", "activeTab", "tabs"
|
||||||
],
|
],
|
||||||
|
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
"matches": ["<all_urls>"],
|
"matches": ["<all_urls>"],
|
||||||
"js": ["content-script.js"]
|
"js": ["content-script.js"]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"content_security_policy": {
|
||||||
|
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'; connect-src 'self' https://api.qortal.org https://api2.qortal.org https://appnode.qortal.org https://apinode.qortalnodes.live https://apinode1.qortalnodes.live https://apinode2.qortalnodes.live https://apinode3.qortalnodes.live https://apinode4.qortalnodes.live;"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
BIN
public/memory-pow.wasm.full
Normal file
BIN
public/memory-pow.wasm.full
Normal file
Binary file not shown.
538
src/App.tsx
538
src/App.tsx
@ -3,14 +3,16 @@ import reactLogo from "./assets/react.svg";
|
|||||||
import viteLogo from "/vite.svg";
|
import viteLogo from "/vite.svg";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
import { useDropzone } from "react-dropzone";
|
import { useDropzone } from "react-dropzone";
|
||||||
import { Box, Input, InputLabel, Tooltip, Typography } from "@mui/material";
|
import { Box, CircularProgress, Input, InputLabel, Tooltip, Typography } from "@mui/material";
|
||||||
import { decryptStoredWallet } from "./utils/decryptWallet";
|
import { decryptStoredWallet } from "./utils/decryptWallet";
|
||||||
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";
|
||||||
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
import Logo2 from "./assets/svgs/Logo2.svg";
|
import Logo2 from "./assets/svgs/Logo2.svg";
|
||||||
import Copy from "./assets/svgs/Copy.svg";
|
import Copy from "./assets/svgs/Copy.svg";
|
||||||
|
import ltcLogo from './assets/ltc.png';
|
||||||
|
import qortLogo from './assets/qort.png'
|
||||||
import { CopyToClipboard } from "react-copy-to-clipboard";
|
import { CopyToClipboard } from "react-copy-to-clipboard";
|
||||||
import Download from "./assets/svgs/Download.svg";
|
import Download from "./assets/svgs/Download.svg";
|
||||||
import Logout from "./assets/svgs/Logout.svg";
|
import Logout from "./assets/svgs/Logout.svg";
|
||||||
@ -55,17 +57,24 @@ type extStates =
|
|||||||
| "transfer-success-regular"
|
| "transfer-success-regular"
|
||||||
| "transfer-success-request"
|
| "transfer-success-request"
|
||||||
| "wallet-dropped"
|
| "wallet-dropped"
|
||||||
|
| "web-app-request-buy-order"
|
||||||
|
| "buy-order-submitted"
|
||||||
;
|
;
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [extState, setExtstate] = useState<extStates>("not-authenticated");
|
const [extState, setExtstate] = useState<extStates>("not-authenticated");
|
||||||
const [backupjson, setBackupjson] = useState<any>(null);
|
const [backupjson, setBackupjson] = useState<any>(null);
|
||||||
const [rawWallet, setRawWallet] = useState<any>(null);
|
const [rawWallet, setRawWallet] = useState<any>(null);
|
||||||
|
const [ltcBalanceLoading, setLtcBalanceLoading] = useState<boolean>(false);
|
||||||
|
const [qortBalanceLoading, setQortBalanceLoading] = useState<boolean>(false)
|
||||||
const [decryptedWallet, setdecryptedWallet] = useState<any>(null);
|
const [decryptedWallet, setdecryptedWallet] = useState<any>(null);
|
||||||
const [requestConnection, setRequestConnection] = useState<any>(null);
|
const [requestConnection, setRequestConnection] = useState<any>(null);
|
||||||
|
const [requestBuyOrder, setRequestBuyOrder] = useState<any>(null);
|
||||||
|
const [authenticatedMode, setAuthenticatedMode] = useState('qort')
|
||||||
const [requestAuthentication, setRequestAuthentication] = useState<any>(null);
|
const [requestAuthentication, setRequestAuthentication] = useState<any>(null);
|
||||||
const [userInfo, setUserInfo] = useState<any>(null);
|
const [userInfo, setUserInfo] = useState<any>(null);
|
||||||
const [balance, setBalance] = useState<any>(null);
|
const [balance, setBalance] = useState<any>(null);
|
||||||
|
const [ltcBalance, setLtcBalance] = useState<any>(null)
|
||||||
const [paymentTo, setPaymentTo] = useState<string>("");
|
const [paymentTo, setPaymentTo] = useState<string>("");
|
||||||
const [paymentAmount, setPaymentAmount] = useState<number>(0);
|
const [paymentAmount, setPaymentAmount] = useState<number>(0);
|
||||||
const [paymentPassword, setPaymentPassword] = useState<string>("");
|
const [paymentPassword, setPaymentPassword] = useState<string>("");
|
||||||
@ -75,7 +84,7 @@ function App() {
|
|||||||
const [walletToBeDownloaded, setWalletToBeDownloaded] = useState<any>(null);
|
const [walletToBeDownloaded, setWalletToBeDownloaded] = useState<any>(null);
|
||||||
const [walletToBeDownloadedPassword, setWalletToBeDownloadedPassword] =
|
const [walletToBeDownloadedPassword, setWalletToBeDownloadedPassword] =
|
||||||
useState<string>("");
|
useState<string>("");
|
||||||
const [authenticatePassword, setAuthenticatePassword] =
|
const [authenticatePassword, setAuthenticatePassword] =
|
||||||
useState<string>("");
|
useState<string>("");
|
||||||
const [sendqortState, setSendqortState] = useState<any>(null);
|
const [sendqortState, setSendqortState] = useState<any>(null);
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false)
|
const [isLoading, setIsLoading] = useState<boolean>(false)
|
||||||
@ -85,11 +94,11 @@ function App() {
|
|||||||
] = useState<string>("");
|
] = useState<string>("");
|
||||||
const [walletToBeDownloadedError, setWalletToBeDownloadedError] =
|
const [walletToBeDownloadedError, setWalletToBeDownloadedError] =
|
||||||
useState<string>("");
|
useState<string>("");
|
||||||
const [walletToBeDecryptedError, setWalletToBeDecryptedError] =
|
const [walletToBeDecryptedError, setWalletToBeDecryptedError] =
|
||||||
useState<string>("");
|
useState<string>("");
|
||||||
const holdRefExtState = useRef<extStates>("not-authenticated")
|
const holdRefExtState = useRef<extStates>("not-authenticated")
|
||||||
useEffect(()=> {
|
useEffect(() => {
|
||||||
if(extState){
|
if (extState) {
|
||||||
holdRefExtState.current = extState
|
holdRefExtState.current = extState
|
||||||
}
|
}
|
||||||
}, [extState])
|
}, [extState])
|
||||||
@ -118,14 +127,14 @@ function App() {
|
|||||||
// Read the file as text
|
// Read the file as text
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
});
|
});
|
||||||
|
|
||||||
let error: any = null;
|
let error: any = null;
|
||||||
let pf: any;
|
let pf: any;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof fileContents !== "string") return;
|
if (typeof fileContents !== "string") return;
|
||||||
pf = JSON.parse(fileContents);
|
pf = JSON.parse(fileContents);
|
||||||
} catch (e) {}
|
} catch (e) { }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const requiredFields = [
|
const requiredFields = [
|
||||||
@ -153,7 +162,7 @@ function App() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const saveWalletFunc = async (password: string) => {
|
const saveWalletFunc = async (password: string) => {
|
||||||
let wallet = structuredClone(rawWallet);
|
let wallet = structuredClone(rawWallet);
|
||||||
@ -163,7 +172,7 @@ function App() {
|
|||||||
wallet = await wallet2.generateSaveWalletData(
|
wallet = await wallet2.generateSaveWalletData(
|
||||||
password,
|
password,
|
||||||
crypto.kdfThreads,
|
crypto.kdfThreads,
|
||||||
() => {}
|
() => { }
|
||||||
);
|
);
|
||||||
|
|
||||||
setWalletToBeDownloaded({
|
setWalletToBeDownloaded({
|
||||||
@ -192,19 +201,30 @@ function App() {
|
|||||||
tabs[0].id,
|
tabs[0].id,
|
||||||
{ from: "popup", subject: "anySubject" },
|
{ from: "popup", subject: "anySubject" },
|
||||||
function (response) {
|
function (response) {
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const getBalanceFunc = () => {
|
const getBalanceFunc = () => {
|
||||||
|
setQortBalanceLoading(true)
|
||||||
chrome.runtime.sendMessage({ action: "balance" }, (response) => {
|
chrome.runtime.sendMessage({ action: "balance" }, (response) => {
|
||||||
if (response && !response?.error) {
|
if (response && !response?.error) {
|
||||||
setBalance(response);
|
setBalance(response);
|
||||||
}
|
}
|
||||||
|
setQortBalanceLoading(false)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const getLtcBalanceFunc = () => {
|
||||||
|
setLtcBalanceLoading(true)
|
||||||
|
chrome.runtime.sendMessage({ action: "ltcBalance" }, (response) => {
|
||||||
|
if (response && !response?.error) {
|
||||||
|
setLtcBalance(response);
|
||||||
|
}
|
||||||
|
setLtcBalanceLoading(false)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const sendCoinFunc = () => {
|
const sendCoinFunc = () => {
|
||||||
@ -253,7 +273,7 @@ function App() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Listen for messages from the background script
|
// Listen for messages from the background script
|
||||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||||
|
|
||||||
// Check if the message is to update the state
|
// Check if the message is to update the state
|
||||||
if (message.action === "UPDATE_STATE_CONFIRM_SEND_QORT") {
|
if (message.action === "UPDATE_STATE_CONFIRM_SEND_QORT") {
|
||||||
// Update the component state with the received 'sendqort' state
|
// Update the component state with the received 'sendqort' state
|
||||||
@ -266,6 +286,10 @@ function App() {
|
|||||||
// Update the component state with the received 'sendqort' state
|
// Update the component state with the received 'sendqort' state
|
||||||
setRequestConnection(message.payload);
|
setRequestConnection(message.payload);
|
||||||
setExtstate("web-app-request-connection");
|
setExtstate("web-app-request-connection");
|
||||||
|
} else if (message.action === "UPDATE_STATE_REQUEST_BUY_ORDER") {
|
||||||
|
// Update the component state with the received 'sendqort' state
|
||||||
|
setRequestBuyOrder(message.payload);
|
||||||
|
setExtstate("web-app-request-buy-order");
|
||||||
} else if (message.action === "UPDATE_STATE_REQUEST_AUTHENTICATION") {
|
} else if (message.action === "UPDATE_STATE_REQUEST_AUTHENTICATION") {
|
||||||
// Update the component state with the received 'sendqort' state
|
// Update the component state with the received 'sendqort' state
|
||||||
setRequestAuthentication(message.payload);
|
setRequestAuthentication(message.payload);
|
||||||
@ -276,7 +300,7 @@ function App() {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
//param = isDecline
|
//param = isDecline
|
||||||
const confirmPayment = (isDecline: boolean) => {
|
const confirmPayment = (isDecline: boolean) => {
|
||||||
if (isDecline) {
|
if (isDecline) {
|
||||||
@ -301,10 +325,7 @@ function App() {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// if (!paymentPassword) {
|
|
||||||
// setSendPaymentError("Please enter your wallet password");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
chrome.runtime.sendMessage(
|
chrome.runtime.sendMessage(
|
||||||
{
|
{
|
||||||
@ -321,9 +342,51 @@ function App() {
|
|||||||
if (response === true) {
|
if (response === true) {
|
||||||
setExtstate("transfer-success-request");
|
setExtstate("transfer-success-request");
|
||||||
setCountdown(null);
|
setCountdown(null);
|
||||||
// setSendPaymentSuccess("Payment successfully sent");
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
setSendPaymentError(
|
||||||
|
response?.error || "Unable to perform payment. Please try again."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmBuyOrder = (isDecline: boolean) => {
|
||||||
|
if (isDecline) {
|
||||||
|
chrome.runtime.sendMessage(
|
||||||
|
{
|
||||||
|
action: "buyOrderConfirmation",
|
||||||
|
payload: {
|
||||||
|
crosschainAtInfo: requestBuyOrder?.crosschainAtInfo,
|
||||||
|
interactionId: requestBuyOrder?.interactionId,
|
||||||
|
isDecline: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
(response) => {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsLoading(true)
|
||||||
|
chrome.runtime.sendMessage(
|
||||||
|
{
|
||||||
|
action: "buyOrderConfirmation",
|
||||||
|
payload: {
|
||||||
|
crosschainAtInfo: requestBuyOrder?.crosschainAtInfo,
|
||||||
|
interactionId: requestBuyOrder?.interactionId,
|
||||||
|
isDecline: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
(response) => {
|
||||||
|
if (response === true) {
|
||||||
|
setExtstate("buy-order-submitted");
|
||||||
|
setCountdown(null);
|
||||||
|
} else {
|
||||||
|
|
||||||
setSendPaymentError(
|
setSendPaymentError(
|
||||||
response?.error || "Unable to perform payment. Please try again."
|
response?.error || "Unable to perform payment. Please try again."
|
||||||
);
|
);
|
||||||
@ -355,18 +418,18 @@ function App() {
|
|||||||
// useEffect(()=> {
|
// useEffect(()=> {
|
||||||
// rawWalletRef.current = rawWallet
|
// rawWalletRef.current = rawWallet
|
||||||
// }, [rawWallet])
|
// }, [rawWallet])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
chrome.runtime.sendMessage({ action: "getWalletInfo" }, (response) => {
|
chrome.runtime.sendMessage({ action: "getWalletInfo" }, (response) => {
|
||||||
if (response && response?.walletInfo) {
|
if (response && response?.walletInfo) {
|
||||||
setRawWallet(response?.walletInfo);
|
setRawWallet(response?.walletInfo);
|
||||||
if(holdRefExtState.current === 'web-app-request-payment' || holdRefExtState.current === 'web-app-request-connection') return
|
if (holdRefExtState.current === 'web-app-request-payment' || holdRefExtState.current === 'web-app-request-connection' || holdRefExtState.current === 'web-app-request-buy-order') return
|
||||||
setExtstate("authenticated");
|
setExtstate("authenticated");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error) {} finally {
|
} catch (error) { } finally {
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
@ -380,7 +443,7 @@ function App() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
getBalanceFunc();
|
getBalanceFunc();
|
||||||
} catch (error) {}
|
} catch (error) { }
|
||||||
}, [address]);
|
}, [address]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -389,6 +452,12 @@ function App() {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(()=> {
|
||||||
|
if(authenticatedMode === 'ltc' && !ltcBalanceLoading && ltcBalance === null ){
|
||||||
|
getLtcBalanceFunc()
|
||||||
|
}
|
||||||
|
}, [authenticatedMode])
|
||||||
|
|
||||||
const confirmPasswordToDownload = async () => {
|
const confirmPasswordToDownload = async () => {
|
||||||
try {
|
try {
|
||||||
setWalletToBeDownloadedError("");
|
setWalletToBeDownloadedError("");
|
||||||
@ -397,8 +466,8 @@ function App() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
await new Promise<void>((res)=> {
|
await new Promise<void>((res) => {
|
||||||
setTimeout(()=> {
|
setTimeout(() => {
|
||||||
res()
|
res()
|
||||||
}, 250)
|
}, 250)
|
||||||
})
|
})
|
||||||
@ -440,8 +509,8 @@ function App() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
await new Promise<void>((res)=> {
|
await new Promise<void>((res) => {
|
||||||
setTimeout(()=> {
|
setTimeout(() => {
|
||||||
res()
|
res()
|
||||||
}, 250)
|
}, 250)
|
||||||
})
|
})
|
||||||
@ -449,12 +518,14 @@ function App() {
|
|||||||
const wallet = await res.generateSaveWalletData(
|
const wallet = await res.generateSaveWalletData(
|
||||||
walletToBeDownloadedPassword,
|
walletToBeDownloadedPassword,
|
||||||
crypto.kdfThreads,
|
crypto.kdfThreads,
|
||||||
() => {}
|
() => { }
|
||||||
);
|
);
|
||||||
chrome.runtime.sendMessage({ action: "decryptWallet", payload: {
|
chrome.runtime.sendMessage({
|
||||||
password: walletToBeDownloadedPassword,
|
action: "decryptWallet", payload: {
|
||||||
wallet
|
password: walletToBeDownloadedPassword,
|
||||||
} }, (response) => {
|
wallet
|
||||||
|
}
|
||||||
|
}, (response) => {
|
||||||
if (response && !response?.error) {
|
if (response && !response?.error) {
|
||||||
setRawWallet(wallet);
|
setRawWallet(wallet);
|
||||||
setWalletToBeDownloaded({
|
setWalletToBeDownloaded({
|
||||||
@ -468,18 +539,18 @@ function App() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
getBalanceFunc();
|
getBalanceFunc();
|
||||||
} else if(response?.error){
|
} else if (response?.error) {
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
setWalletToBeDecryptedError(response.error)
|
setWalletToBeDecryptedError(response.error)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
setWalletToBeDownloadedError(error?.message);
|
setWalletToBeDownloadedError(error?.message);
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const logoutFunc = () => {
|
const logoutFunc = () => {
|
||||||
@ -489,7 +560,7 @@ function App() {
|
|||||||
resetAllStates();
|
resetAllStates();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error) {}
|
} catch (error) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
const returnToMain = () => {
|
const returnToMain = () => {
|
||||||
@ -510,9 +581,11 @@ function App() {
|
|||||||
setRawWallet(null);
|
setRawWallet(null);
|
||||||
setdecryptedWallet(null);
|
setdecryptedWallet(null);
|
||||||
setRequestConnection(null);
|
setRequestConnection(null);
|
||||||
|
setRequestBuyOrder(null)
|
||||||
setRequestAuthentication(null);
|
setRequestAuthentication(null);
|
||||||
setUserInfo(null);
|
setUserInfo(null);
|
||||||
setBalance(null);
|
setBalance(null);
|
||||||
|
setLtcBalance(null)
|
||||||
setPaymentTo("");
|
setPaymentTo("");
|
||||||
setPaymentAmount(0);
|
setPaymentAmount(0);
|
||||||
setPaymentPassword("");
|
setPaymentPassword("");
|
||||||
@ -526,19 +599,21 @@ function App() {
|
|||||||
setSendqortState(null);
|
setSendqortState(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const authenticateWallet = async()=> {
|
const authenticateWallet = async () => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
setWalletToBeDecryptedError('')
|
setWalletToBeDecryptedError('')
|
||||||
await new Promise<void>((res)=> {
|
await new Promise<void>((res) => {
|
||||||
setTimeout(()=> {
|
setTimeout(() => {
|
||||||
res()
|
res()
|
||||||
}, 250)
|
}, 250)
|
||||||
})
|
})
|
||||||
chrome.runtime.sendMessage({ action: "decryptWallet", payload: {
|
chrome.runtime.sendMessage({
|
||||||
password: authenticatePassword,
|
action: "decryptWallet", payload: {
|
||||||
wallet: rawWallet
|
password: authenticatePassword,
|
||||||
} }, (response) => {
|
wallet: rawWallet
|
||||||
|
}
|
||||||
|
}, (response) => {
|
||||||
if (response && !response?.error) {
|
if (response && !response?.error) {
|
||||||
setAuthenticatePassword("");
|
setAuthenticatePassword("");
|
||||||
setExtstate("authenticated");
|
setExtstate("authenticated");
|
||||||
@ -550,14 +625,14 @@ function App() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
getBalanceFunc();
|
getBalanceFunc();
|
||||||
} else if(response?.error){
|
} else if (response?.error) {
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
setWalletToBeDecryptedError(response.error)
|
setWalletToBeDecryptedError(response.error)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setWalletToBeDecryptedError('Unable to authenticate. Wrong password')
|
setWalletToBeDecryptedError('Unable to authenticate. Wrong password')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -636,55 +711,91 @@ function App() {
|
|||||||
<AuthenticatedContainer>
|
<AuthenticatedContainer>
|
||||||
<AuthenticatedContainerInnerLeft>
|
<AuthenticatedContainerInnerLeft>
|
||||||
<Spacer height="48px" />
|
<Spacer height="48px" />
|
||||||
<img src={Logo2} />
|
|
||||||
<Spacer height="32px" />
|
|
||||||
<TextP
|
|
||||||
sx={{
|
|
||||||
textAlign: "center",
|
|
||||||
lineHeight: "24px",
|
|
||||||
fontSize: "20px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{userInfo?.name}
|
|
||||||
</TextP>
|
|
||||||
<Spacer height="10px" />
|
|
||||||
<CopyToClipboard text={rawWallet?.address0}>
|
|
||||||
<AddressBox>
|
|
||||||
{rawWallet?.address0?.slice(0, 6)}...
|
|
||||||
{rawWallet?.address0?.slice(-4)} <img src={Copy} />
|
|
||||||
</AddressBox>
|
|
||||||
</CopyToClipboard>
|
|
||||||
<Spacer height="10px" />
|
|
||||||
{(balance >= 0) && (
|
|
||||||
<TextP
|
|
||||||
sx={{
|
|
||||||
textAlign: "center",
|
|
||||||
lineHeight: "24px",
|
|
||||||
fontSize: "20px",
|
|
||||||
fontWeight: 700,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{balance?.toFixed(2)} QORT
|
|
||||||
</TextP>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* <p>balance: {balance}</p> */}
|
|
||||||
<Spacer height="55px" />
|
|
||||||
|
|
||||||
{/* <CustomButton
|
{authenticatedMode === 'ltc' ? (
|
||||||
onClick={() => {
|
<>
|
||||||
setExtstate("download-wallet");
|
<img src={ltcLogo} />
|
||||||
}}
|
<Spacer height="32px" />
|
||||||
>
|
<CopyToClipboard text={rawWallet?.ltcAddress}>
|
||||||
Download Wallet
|
<AddressBox>
|
||||||
</CustomButton> */}
|
{rawWallet?.ltcAddress?.slice(0, 6)}...
|
||||||
<CustomButton
|
{rawWallet?.ltcAddress?.slice(-4)} <img src={Copy} />
|
||||||
onClick={() => {
|
</AddressBox>
|
||||||
setExtstate("send-qort");
|
</CopyToClipboard>
|
||||||
}}
|
<Spacer height="10px" />
|
||||||
>
|
{ltcBalanceLoading && <CircularProgress color="success" size={16} />}
|
||||||
Transfer QORT
|
{ltcBalance && !isNaN(+ltcBalance) && !ltcBalanceLoading && (
|
||||||
</CustomButton>
|
<Box sx={{
|
||||||
|
gap: '10px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}>
|
||||||
|
<TextP
|
||||||
|
sx={{
|
||||||
|
textAlign: "center",
|
||||||
|
lineHeight: "24px",
|
||||||
|
fontSize: "20px",
|
||||||
|
fontWeight: 700,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ltcBalance} LTC
|
||||||
|
</TextP>
|
||||||
|
<RefreshIcon onClick={getLtcBalanceFunc} sx={{
|
||||||
|
fontSize: '16px',
|
||||||
|
color: 'white',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}} />
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
)}
|
||||||
|
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<img src={Logo2} />
|
||||||
|
<Spacer height="32px" />
|
||||||
|
<TextP
|
||||||
|
sx={{
|
||||||
|
textAlign: "center",
|
||||||
|
lineHeight: "24px",
|
||||||
|
fontSize: "20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{userInfo?.name}
|
||||||
|
</TextP>
|
||||||
|
<Spacer height="10px" />
|
||||||
|
<CopyToClipboard text={rawWallet?.address0}>
|
||||||
|
<AddressBox>
|
||||||
|
{rawWallet?.address0?.slice(0, 6)}...
|
||||||
|
{rawWallet?.address0?.slice(-4)} <img src={Copy} />
|
||||||
|
</AddressBox>
|
||||||
|
</CopyToClipboard>
|
||||||
|
<Spacer height="10px" />
|
||||||
|
{qortBalanceLoading && <CircularProgress color="success" size={16} />}
|
||||||
|
{balance && (
|
||||||
|
<TextP
|
||||||
|
sx={{
|
||||||
|
textAlign: "center",
|
||||||
|
lineHeight: "24px",
|
||||||
|
fontSize: "20px",
|
||||||
|
fontWeight: 700,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{balance} QORT
|
||||||
|
</TextP>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Spacer height="55px" />
|
||||||
|
<CustomButton
|
||||||
|
onClick={() => {
|
||||||
|
setExtstate("send-qort");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Transfer QORT
|
||||||
|
</CustomButton>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
</AuthenticatedContainerInnerLeft>
|
</AuthenticatedContainerInnerLeft>
|
||||||
<AuthenticatedContainerInnerRight>
|
<AuthenticatedContainerInnerRight>
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
@ -705,6 +816,25 @@ function App() {
|
|||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Spacer height="20px" />
|
||||||
|
{authenticatedMode === 'qort' && (
|
||||||
|
<img onClick={() => {
|
||||||
|
setAuthenticatedMode('ltc')
|
||||||
|
}} src={ltcLogo} style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
width: '20px',
|
||||||
|
height: 'auto'
|
||||||
|
}} />
|
||||||
|
)}
|
||||||
|
{authenticatedMode === 'ltc' && (
|
||||||
|
<img onClick={() => {
|
||||||
|
setAuthenticatedMode('qort')
|
||||||
|
}} src={qortLogo} style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
width: '20px',
|
||||||
|
height: 'auto'
|
||||||
|
}} />
|
||||||
|
)}
|
||||||
</AuthenticatedContainerInnerRight>
|
</AuthenticatedContainerInnerRight>
|
||||||
</AuthenticatedContainer>
|
</AuthenticatedContainer>
|
||||||
)}
|
)}
|
||||||
@ -766,7 +896,7 @@ function App() {
|
|||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{balance?.toFixed(2)} QORT
|
{balance} QORT
|
||||||
</TextP>
|
</TextP>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer height="35px" />
|
<Spacer height="35px" />
|
||||||
@ -817,6 +947,91 @@ function App() {
|
|||||||
</CustomButton>
|
</CustomButton>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{extState === "web-app-request-buy-order" && (
|
||||||
|
<>
|
||||||
|
<Spacer height="100px" />
|
||||||
|
|
||||||
|
<TextP
|
||||||
|
sx={{
|
||||||
|
textAlign: "center",
|
||||||
|
lineHeight: "15px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
The Application <br></br>{" "}
|
||||||
|
<TextItalic>{requestBuyOrder?.hostname}</TextItalic> <br></br>
|
||||||
|
<TextSpan>is requesting a buy order</TextSpan>
|
||||||
|
</TextP>
|
||||||
|
<Spacer height="10px" />
|
||||||
|
<TextP
|
||||||
|
sx={{
|
||||||
|
textAlign: "center",
|
||||||
|
lineHeight: "24px",
|
||||||
|
fontSize: "20px",
|
||||||
|
fontWeight: 700,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{+requestBuyOrder?.crosschainAtInfo?.qortAmount} QORT
|
||||||
|
</TextP>
|
||||||
|
<Spacer height="15px" />
|
||||||
|
<TextP
|
||||||
|
sx={{
|
||||||
|
textAlign: "center",
|
||||||
|
lineHeight: "15px",
|
||||||
|
fontSize: "14px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
FOR
|
||||||
|
</TextP>
|
||||||
|
<Spacer height="15px" />
|
||||||
|
<TextP
|
||||||
|
sx={{
|
||||||
|
textAlign: "center",
|
||||||
|
lineHeight: "24px",
|
||||||
|
fontSize: "20px",
|
||||||
|
fontWeight: 700,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{requestBuyOrder?.crosschainAtInfo?.expectedForeignAmount} {requestBuyOrder?.crosschainAtInfo?.foreignBlockchain}
|
||||||
|
</TextP>
|
||||||
|
{/* <Spacer height="29px" />
|
||||||
|
|
||||||
|
<CustomLabel htmlFor="standard-adornment-password">
|
||||||
|
Confirm Wallet Password
|
||||||
|
</CustomLabel>
|
||||||
|
<Spacer height="5px" />
|
||||||
|
<PasswordField
|
||||||
|
id="standard-adornment-password"
|
||||||
|
value={paymentPassword}
|
||||||
|
onChange={(e) => setPaymentPassword(e.target.value)}
|
||||||
|
/> */}
|
||||||
|
<Spacer height="29px" />
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "14px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CustomButton
|
||||||
|
sx={{
|
||||||
|
minWidth: "102px",
|
||||||
|
}}
|
||||||
|
onClick={() => confirmBuyOrder(false)}
|
||||||
|
>
|
||||||
|
accept
|
||||||
|
</CustomButton>
|
||||||
|
<CustomButton
|
||||||
|
sx={{
|
||||||
|
minWidth: "102px",
|
||||||
|
}}
|
||||||
|
onClick={() => confirmBuyOrder(true)}
|
||||||
|
>
|
||||||
|
decline
|
||||||
|
</CustomButton>
|
||||||
|
</Box>
|
||||||
|
<ErrorText>{sendPaymentError}</ErrorText>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{extState === "web-app-request-payment" && (
|
{extState === "web-app-request-payment" && (
|
||||||
<>
|
<>
|
||||||
<Spacer height="100px" />
|
<Spacer height="100px" />
|
||||||
@ -1011,7 +1226,7 @@ function App() {
|
|||||||
style={{
|
style={{
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
onClick={()=> {
|
onClick={() => {
|
||||||
setRawWallet(null);
|
setRawWallet(null);
|
||||||
setExtstate("not-authenticated");
|
setExtstate("not-authenticated");
|
||||||
}}
|
}}
|
||||||
@ -1046,32 +1261,32 @@ function App() {
|
|||||||
</TextP>
|
</TextP>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer height="35px" />
|
<Spacer height="35px" />
|
||||||
|
|
||||||
<>
|
<>
|
||||||
<CustomLabel htmlFor="standard-adornment-password">
|
<CustomLabel htmlFor="standard-adornment-password">
|
||||||
Wallet Password
|
Wallet Password
|
||||||
</CustomLabel>
|
</CustomLabel>
|
||||||
<Spacer height="5px" />
|
<Spacer height="5px" />
|
||||||
<PasswordField
|
<PasswordField
|
||||||
id="standard-adornment-password"
|
id="standard-adornment-password"
|
||||||
value={authenticatePassword}
|
value={authenticatePassword}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setAuthenticatePassword(e.target.value)
|
setAuthenticatePassword(e.target.value)
|
||||||
|
}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
authenticateWallet();
|
||||||
}
|
}
|
||||||
onKeyDown={(e) => {
|
}}
|
||||||
if (e.key === "Enter") {
|
/>
|
||||||
authenticateWallet();
|
<Spacer height="20px" />
|
||||||
}
|
<CustomButton onClick={authenticateWallet} >
|
||||||
}}
|
Authenticate
|
||||||
/>
|
</CustomButton>
|
||||||
<Spacer height="20px" />
|
<ErrorText>
|
||||||
<CustomButton onClick={authenticateWallet} >
|
{walletToBeDecryptedError}
|
||||||
Authenticate
|
</ErrorText>
|
||||||
</CustomButton>
|
</>
|
||||||
<ErrorText>
|
|
||||||
{walletToBeDecryptedError}
|
|
||||||
</ErrorText>
|
|
||||||
</>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{extState === "download-wallet" && (
|
{extState === "download-wallet" && (
|
||||||
@ -1158,34 +1373,34 @@ function App() {
|
|||||||
<>
|
<>
|
||||||
{!walletToBeDownloaded && (
|
{!walletToBeDownloaded && (
|
||||||
<>
|
<>
|
||||||
<Spacer height="22px" />
|
<Spacer height="22px" />
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
justifyContent: "flex-start",
|
justifyContent: "flex-start",
|
||||||
paddingLeft: "22px",
|
paddingLeft: "22px",
|
||||||
boxSizing: "border-box",
|
boxSizing: "border-box",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
style={{
|
style={{
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
onClick={()=> {
|
onClick={() => {
|
||||||
setExtstate("not-authenticated")
|
setExtstate("not-authenticated")
|
||||||
}}
|
}}
|
||||||
src={Return}
|
src={Return}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer height="15px" />
|
<Spacer height="15px" />
|
||||||
<div className="image-container" style={{
|
<div className="image-container" style={{
|
||||||
width: '136px',
|
width: '136px',
|
||||||
height: '154px'
|
height: '154px'
|
||||||
}}>
|
}}>
|
||||||
<img src={Logo1} className="base-image" />
|
<img src={Logo1} className="base-image" />
|
||||||
<img src={Logo1Dark} className="hover-image" />
|
<img src={Logo1Dark} className="hover-image" />
|
||||||
</div>
|
</div>
|
||||||
<Spacer height="38px" />
|
<Spacer height="38px" />
|
||||||
<TextP
|
<TextP
|
||||||
sx={{
|
sx={{
|
||||||
@ -1302,6 +1517,29 @@ function App() {
|
|||||||
</CustomButton>
|
</CustomButton>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{extState === "buy-order-submitted" && (
|
||||||
|
<>
|
||||||
|
<Spacer height="48px" />
|
||||||
|
<img src={Success} />
|
||||||
|
<Spacer height="45px" />
|
||||||
|
<TextP
|
||||||
|
sx={{
|
||||||
|
textAlign: "center",
|
||||||
|
lineHeight: "15px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Your buy order was submitted
|
||||||
|
</TextP>
|
||||||
|
<Spacer height="100px" />
|
||||||
|
<CustomButton
|
||||||
|
onClick={() => {
|
||||||
|
window.close();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</CustomButton>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{countdown && (
|
{countdown && (
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
|
BIN
src/assets/ltc.png
Normal file
BIN
src/assets/ltc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
src/assets/qort.png
Normal file
BIN
src/assets/qort.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
@ -1,19 +1,13 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import Base58 from "./deps/Base58";
|
import Base58 from "./deps/Base58";
|
||||||
|
import { signChat } from "./transactions/signChat";
|
||||||
import { createTransaction } from "./transactions/transactions";
|
import { createTransaction } from "./transactions/transactions";
|
||||||
import { decryptChatMessage } from "./utils/decryptChatMessage";
|
import { decryptChatMessage } from "./utils/decryptChatMessage";
|
||||||
import { decryptStoredWallet } from "./utils/decryptWallet";
|
import { decryptStoredWallet } from "./utils/decryptWallet";
|
||||||
import PhraseWallet from "./utils/generateWallet/phrase-wallet";
|
import PhraseWallet from "./utils/generateWallet/phrase-wallet";
|
||||||
import { validateAddress } from "./utils/validateAddress";
|
import { validateAddress } from "./utils/validateAddress";
|
||||||
|
import { Sha256 } from 'asmcrypto.js'
|
||||||
|
|
||||||
// chrome.storage.local.clear(function() {
|
|
||||||
// var error = chrome.runtime.lastError;
|
|
||||||
// if (error) {
|
|
||||||
// console.error(error);
|
|
||||||
// } else {
|
|
||||||
// console.log('Local storage cleared');
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
export const walletVersion = 2;
|
export const walletVersion = 2;
|
||||||
// List of your API endpoints
|
// List of your API endpoints
|
||||||
@ -28,6 +22,9 @@ const apiEndpoints = [
|
|||||||
"https://apinode4.qortalnodes.live",
|
"https://apinode4.qortalnodes.live",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const buyTradeNodeBaseUrl = 'https://appnode.qortal.org'
|
||||||
|
const proxyAccountAddress = 'QXPejUe5Za1KD3zCMViWCX35AreMQ9H7ku'
|
||||||
|
const proxyAccountPublicKey = '5hP6stDWybojoDw5t8z9D51nV945oMPX7qBd29rhX1G7'
|
||||||
const pendingResponses = new Map();
|
const pendingResponses = new Map();
|
||||||
|
|
||||||
// Function to check each API endpoint
|
// Function to check each API endpoint
|
||||||
@ -114,6 +111,13 @@ async function connection(hostname) {
|
|||||||
return isConnected;
|
return isConnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getTradeInfo(qortalAtAddress) {
|
||||||
|
const response = await fetch(buyTradeNodeBaseUrl + "/crosschain/trade/" + qortalAtAddress);
|
||||||
|
if (!response?.ok) throw new Error("Cannot crosschain trade information");
|
||||||
|
const data = await response.json();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
async function getBalanceInfo() {
|
async function getBalanceInfo() {
|
||||||
const wallet = await getSaveWallet();
|
const wallet = await getSaveWallet();
|
||||||
const address = wallet.address0;
|
const address = wallet.address0;
|
||||||
@ -124,6 +128,45 @@ async function getBalanceInfo() {
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
async function getLTCBalance() {
|
||||||
|
const wallet = await getSaveWallet();
|
||||||
|
let _url = `${buyTradeNodeBaseUrl}/crosschain/ltc/walletbalance`;
|
||||||
|
const keyPair = await getKeyPair()
|
||||||
|
const parsedKeyPair = JSON.parse(keyPair)
|
||||||
|
let _body = parsedKeyPair.ltcPublicKey
|
||||||
|
const response = await fetch(_url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: _body
|
||||||
|
});
|
||||||
|
if(response?.ok){
|
||||||
|
const data = await response.text();
|
||||||
|
const dataLTCBalance = (Number(data) / 1e8).toFixed(8);
|
||||||
|
return +dataLTCBalance
|
||||||
|
|
||||||
|
} else throw new Error('Onable to get LTC balance')
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const processTransactionVersion2Chat = async (body: any, validApi: string) => {
|
||||||
|
// const validApi = await findUsableApi();
|
||||||
|
const url = validApi + "/transactions/process?apiVersion=2";
|
||||||
|
return fetch(url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {},
|
||||||
|
body: Base58.encode(body),
|
||||||
|
}).then(async (response) => {
|
||||||
|
try {
|
||||||
|
const json = await response.clone().json();
|
||||||
|
return json;
|
||||||
|
} catch (e) {
|
||||||
|
return await response.text();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const processTransactionVersion2 = async (body: any, validApi: string) => {
|
const processTransactionVersion2 = async (body: any, validApi: string) => {
|
||||||
// const validApi = await findUsableApi();
|
// const validApi = await findUsableApi();
|
||||||
@ -232,14 +275,19 @@ async function getNameOrAddress(receiver) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function decryptWallet({password, wallet, walletVersion}) {
|
async function decryptWallet({ password, wallet, walletVersion }) {
|
||||||
try {
|
try {
|
||||||
const response = await decryptStoredWallet(password, wallet);
|
const response = await decryptStoredWallet(password, wallet);
|
||||||
const wallet2 = new PhraseWallet(response, walletVersion);
|
const wallet2 = new PhraseWallet(response, walletVersion);
|
||||||
const keyPair = wallet2._addresses[0].keyPair;
|
const keyPair = wallet2._addresses[0].keyPair;
|
||||||
|
const ltcPrivateKey = wallet2._addresses[0].ltcWallet.derivedMasterPrivateKey
|
||||||
|
const ltcPublicKey = wallet2._addresses[0].ltcWallet.derivedMasterPublicKey
|
||||||
|
const ltcAddress = wallet2._addresses[0].ltcWallet.address
|
||||||
const toSave = {
|
const toSave = {
|
||||||
privateKey: Base58.encode(keyPair.privateKey),
|
privateKey: Base58.encode(keyPair.privateKey),
|
||||||
publicKey: Base58.encode(keyPair.publicKey)
|
publicKey: Base58.encode(keyPair.publicKey),
|
||||||
|
ltcPrivateKey: ltcPrivateKey,
|
||||||
|
ltcPublicKey : ltcPublicKey
|
||||||
}
|
}
|
||||||
const dataString = JSON.stringify(toSave)
|
const dataString = JSON.stringify(toSave)
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
@ -253,7 +301,8 @@ async function decryptWallet({password, wallet, walletVersion}) {
|
|||||||
});
|
});
|
||||||
const newWallet = {
|
const newWallet = {
|
||||||
...wallet,
|
...wallet,
|
||||||
publicKey: Base58.encode(keyPair.publicKey)
|
publicKey: Base58.encode(keyPair.publicKey),
|
||||||
|
ltcAddress: ltcAddress
|
||||||
}
|
}
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
chrome.storage.local.set({ walletInfo: newWallet }, () => {
|
chrome.storage.local.set({ walletInfo: newWallet }, () => {
|
||||||
@ -265,9 +314,163 @@ async function decryptWallet({password, wallet, walletVersion}) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.log({ error })
|
||||||
|
throw new Error(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function signChatFunc(chatBytesArray, chatNonce, validApi, keyPair) {
|
||||||
|
let response
|
||||||
|
try {
|
||||||
|
const signedChatBytes = signChat(
|
||||||
|
chatBytesArray,
|
||||||
|
chatNonce,
|
||||||
|
keyPair
|
||||||
|
)
|
||||||
|
const res = await processTransactionVersion2Chat(signedChatBytes, validApi)
|
||||||
|
response = res
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
console.error(e.message)
|
||||||
|
response = false
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
function sbrk(size, heap) {
|
||||||
|
let brk = 512 * 1024 // stack top
|
||||||
|
let old = brk
|
||||||
|
brk += size
|
||||||
|
if (brk > heap.length) throw new Error('heap exhausted')
|
||||||
|
return old
|
||||||
|
}
|
||||||
|
|
||||||
|
const computePow = async ({ chatBytes, path, difficulty }) => {
|
||||||
|
let response = null
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
const _chatBytesArray = Object.keys(chatBytes).map(function (key) {
|
||||||
|
return chatBytes[key]
|
||||||
|
})
|
||||||
|
const chatBytesArray = new Uint8Array(_chatBytesArray)
|
||||||
|
const chatBytesHash = new Sha256().process(chatBytesArray).finish().result
|
||||||
|
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
|
||||||
|
const heap = new Uint8Array(memory.buffer)
|
||||||
|
|
||||||
|
const hashPtr = sbrk(32, heap)
|
||||||
|
const hashAry = new Uint8Array(memory.buffer, hashPtr, 32)
|
||||||
|
hashAry.set(chatBytesHash)
|
||||||
|
const workBufferLength = 8 * 1024 * 1024
|
||||||
|
const workBufferPtr = sbrk(workBufferLength, heap)
|
||||||
|
const importObject = {
|
||||||
|
env: {
|
||||||
|
memory: memory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function loadWebAssembly(filename, imports) {
|
||||||
|
// Fetch the file and compile it
|
||||||
|
return fetch(filename).then(response => response.arrayBuffer()).then(buffer => WebAssembly.compile(buffer)).then(module => {
|
||||||
|
// Create the instance.
|
||||||
|
return new WebAssembly.Instance(module, importObject)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
loadWebAssembly(path)
|
||||||
|
.then(wasmModule => {
|
||||||
|
response = {
|
||||||
|
nonce: wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty), chatBytesArray
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendChat({ qortAddress, recipientPublicKey, message }) {
|
||||||
|
|
||||||
|
let _reference = new Uint8Array(64);
|
||||||
|
self.crypto.getRandomValues(_reference);
|
||||||
|
|
||||||
|
let sendTimestamp = Date.now()
|
||||||
|
|
||||||
|
let reference = Base58.encode(_reference)
|
||||||
|
const resKeyPair = await getKeyPair()
|
||||||
|
const parsedData = JSON.parse(resKeyPair)
|
||||||
|
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
|
||||||
|
const uint8PublicKey = Base58.decode(parsedData.publicKey);
|
||||||
|
const keyPair = {
|
||||||
|
privateKey: uint8PrivateKey,
|
||||||
|
publicKey: uint8PublicKey
|
||||||
|
};
|
||||||
|
const difficulty = 8;
|
||||||
|
const jsonData = {
|
||||||
|
atAddress: message.atAddress,
|
||||||
|
foreignKey: message.foreignKey,
|
||||||
|
receivingAddress: message.receivingAddress
|
||||||
|
};
|
||||||
|
const finalJson = {
|
||||||
|
callRequest: jsonData,
|
||||||
|
extra: "whatever additional data goes here"
|
||||||
|
};
|
||||||
|
const messageStringified = JSON.stringify(finalJson)
|
||||||
|
const { chatBytes } = await createTransaction(
|
||||||
|
18,
|
||||||
|
keyPair,
|
||||||
|
{
|
||||||
|
timestamp: sendTimestamp,
|
||||||
|
recipient: qortAddress,
|
||||||
|
recipientPublicKey: recipientPublicKey,
|
||||||
|
hasChatReference: 0,
|
||||||
|
message: messageStringified,
|
||||||
|
lastReference: reference,
|
||||||
|
proofOfWorkNonce: 0,
|
||||||
|
isEncrypted: 1,
|
||||||
|
isText: 1
|
||||||
|
},
|
||||||
|
|
||||||
|
)
|
||||||
|
const path = chrome.runtime.getURL('memory-pow.wasm.full');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const { nonce, chatBytesArray } = await computePow({ chatBytes, path, difficulty })
|
||||||
|
let _response = await signChatFunc(chatBytesArray,
|
||||||
|
nonce, "https://appnode.qortal.org", keyPair
|
||||||
|
)
|
||||||
|
if (_response?.error) {
|
||||||
|
throw new Error(_response?.message)
|
||||||
|
}
|
||||||
|
return _response
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createBuyOrderTx({ crosschainAtInfo }) {
|
||||||
|
try {
|
||||||
|
const wallet = await getSaveWallet();
|
||||||
|
const address = wallet.address0;
|
||||||
|
|
||||||
|
const resKeyPair = await getKeyPair()
|
||||||
|
const parsedData = JSON.parse(resKeyPair)
|
||||||
|
const message = {
|
||||||
|
atAddress: crosschainAtInfo.qortalAtAddress,
|
||||||
|
foreignKey: parsedData.ltcPrivateKey,
|
||||||
|
receivingAddress: address
|
||||||
|
}
|
||||||
|
const res = await sendChat({ qortAddress: proxyAccountAddress, recipientPublicKey: proxyAccountPublicKey, message })
|
||||||
|
if (res?.signature) {
|
||||||
|
|
||||||
|
listenForChatMessageForBuyOrder({
|
||||||
|
nodeBaseUrl: buyTradeNodeBaseUrl,
|
||||||
|
senderAddress: proxyAccountAddress,
|
||||||
|
senderPublicKey: proxyAccountPublicKey,
|
||||||
|
signature: res?.signature,
|
||||||
|
|
||||||
|
})
|
||||||
|
return { atAddress: crosschainAtInfo.qortalAtAddress, chatSignature: res?.signature, node: buyTradeNodeBaseUrl, qortAddress: address }
|
||||||
|
} else {
|
||||||
|
throw new Error("Unable to send buy order message")
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log({error})
|
|
||||||
throw new Error(error.message);
|
throw new Error(error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,7 +482,7 @@ async function sendCoin({ password, amount, receiver }, skipConfirmPassword) {
|
|||||||
throw new Error("Invalid receiver address or name");
|
throw new Error("Invalid receiver address or name");
|
||||||
const wallet = await getSaveWallet();
|
const wallet = await getSaveWallet();
|
||||||
let keyPair = ''
|
let keyPair = ''
|
||||||
if(skipConfirmPassword){
|
if (skipConfirmPassword) {
|
||||||
const resKeyPair = await getKeyPair()
|
const resKeyPair = await getKeyPair()
|
||||||
const parsedData = JSON.parse(resKeyPair)
|
const parsedData = JSON.parse(resKeyPair)
|
||||||
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
|
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
|
||||||
@ -290,11 +493,11 @@ async function sendCoin({ password, amount, receiver }, skipConfirmPassword) {
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const response = await decryptStoredWallet(password, wallet);
|
const response = await decryptStoredWallet(password, wallet);
|
||||||
const wallet2 = new PhraseWallet(response, walletVersion);
|
const wallet2 = new PhraseWallet(response, walletVersion);
|
||||||
|
|
||||||
keyPair = wallet2._addresses[0].keyPair
|
keyPair = wallet2._addresses[0].keyPair
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const lastRef = await getLastRef();
|
const lastRef = await getLastRef();
|
||||||
const fee = await sendQortFee();
|
const fee = await sendQortFee();
|
||||||
@ -316,31 +519,86 @@ async function sendCoin({ password, amount, receiver }, skipConfirmPassword) {
|
|||||||
|
|
||||||
function fetchMessages(apiCall) {
|
function fetchMessages(apiCall) {
|
||||||
let retryDelay = 2000; // Start with a 2-second delay
|
let retryDelay = 2000; // Start with a 2-second delay
|
||||||
const maxDuration = 360000; // Maximum duration set to 6 minutes
|
const maxDuration = 360000 * 2; // Maximum duration set to 12 minutes
|
||||||
const startTime = Date.now(); // Record the start time
|
const startTime = Date.now(); // Record the start time
|
||||||
|
|
||||||
// Promise to handle polling logic
|
// Promise to handle polling logic
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const attemptFetch = async () => {
|
const attemptFetch = async () => {
|
||||||
if (Date.now() - startTime > maxDuration) {
|
if (Date.now() - startTime > maxDuration) {
|
||||||
return reject(new Error("Maximum polling time exceeded"));
|
return reject(new Error("Maximum polling time exceeded"));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(apiCall);
|
const response = await fetch(apiCall);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data && data.length > 0) {
|
if (data && data.length > 0) {
|
||||||
resolve(data[0]); // Resolve the promise when data is found
|
resolve(data[0]); // Resolve the promise when data is found
|
||||||
} else {
|
} else {
|
||||||
setTimeout(attemptFetch, retryDelay);
|
setTimeout(attemptFetch, retryDelay);
|
||||||
retryDelay = Math.min(retryDelay * 2, 360000); // Ensure delay does not exceed 6 minutes
|
retryDelay = Math.min(retryDelay * 2, 360000); // Ensure delay does not exceed 6 minutes
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
reject(error); // Reject the promise on error
|
reject(error); // Reject the promise on error
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
attemptFetch(); // Initial call to start the polling
|
attemptFetch(); // Initial call to start the polling
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchMessagesForBuyOrders(apiCall, signature, senderPublicKey) {
|
||||||
|
let retryDelay = 2000; // Start with a 2-second delay
|
||||||
|
const maxDuration = 360000 * 2; // Maximum duration set to 12 minutes
|
||||||
|
const startTime = Date.now(); // Record the start time
|
||||||
|
let triedChatMessage = []
|
||||||
|
// Promise to handle polling logic
|
||||||
|
await new Promise((res)=> {
|
||||||
|
setTimeout(() => {
|
||||||
|
res()
|
||||||
|
}, 40000);
|
||||||
|
})
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const attemptFetch = async () => {
|
||||||
|
if (Date.now() - startTime > maxDuration) {
|
||||||
|
return reject(new Error("Maximum polling time exceeded"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(apiCall);
|
||||||
|
let data = await response.json();
|
||||||
|
data = data.filter((item) => !triedChatMessage.includes(item.signature))
|
||||||
|
if (data && data.length > 0) {
|
||||||
|
const encodedMessageObj = data[0]
|
||||||
|
const resKeyPair = await getKeyPair()
|
||||||
|
const parsedData = JSON.parse(resKeyPair)
|
||||||
|
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
|
||||||
|
const uint8PublicKey = Base58.decode(parsedData.publicKey);
|
||||||
|
const keyPair = {
|
||||||
|
privateKey: uint8PrivateKey,
|
||||||
|
publicKey: uint8PublicKey
|
||||||
|
};
|
||||||
|
|
||||||
|
const decodedMessage = decryptChatMessage(encodedMessageObj.data, keyPair.privateKey, senderPublicKey, encodedMessageObj.reference)
|
||||||
|
const parsedMessage = JSON.parse(decodedMessage)
|
||||||
|
if (parsedMessage?.extra?.chatRequestSignature === signature) {
|
||||||
|
resolve(parsedMessage);
|
||||||
|
} else {
|
||||||
|
triedChatMessage.push(encodedMessageObj.signature)
|
||||||
|
setTimeout(attemptFetch, retryDelay);
|
||||||
|
retryDelay = Math.min(retryDelay * 2, 360000); // Ensure delay does not exceed 6 minutes
|
||||||
|
}
|
||||||
|
// Resolve the promise when data is found
|
||||||
|
} else {
|
||||||
|
setTimeout(attemptFetch, retryDelay);
|
||||||
|
retryDelay = Math.min(retryDelay * 2, 360000); // Ensure delay does not exceed 6 minutes
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
reject(error); // Reject the promise on error
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
attemptFetch(); // Initial call to start the polling
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,17 +619,17 @@ async function listenForChatMessage({ nodeBaseUrl, senderAddress, senderPublicKe
|
|||||||
const after = timestamp - 5000
|
const after = timestamp - 5000
|
||||||
const apiCall = `${validApi}/chat/messages?involving=${senderAddress}&involving=${address}&reverse=true&limit=1&before=${before}&after=${after}`;
|
const apiCall = `${validApi}/chat/messages?involving=${senderAddress}&involving=${address}&reverse=true&limit=1&before=${before}&after=${after}`;
|
||||||
const encodedMessageObj = await fetchMessages(apiCall)
|
const encodedMessageObj = await fetchMessages(apiCall)
|
||||||
|
|
||||||
const resKeyPair = await getKeyPair()
|
const resKeyPair = await getKeyPair()
|
||||||
const parsedData = JSON.parse(resKeyPair)
|
const parsedData = JSON.parse(resKeyPair)
|
||||||
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
|
const uint8PrivateKey = Base58.decode(parsedData.privateKey);
|
||||||
const uint8PublicKey = Base58.decode(parsedData.publicKey);
|
const uint8PublicKey = Base58.decode(parsedData.publicKey);
|
||||||
const keyPair = {
|
const keyPair = {
|
||||||
privateKey: uint8PrivateKey,
|
privateKey: uint8PrivateKey,
|
||||||
publicKey: uint8PublicKey
|
publicKey: uint8PublicKey
|
||||||
};
|
};
|
||||||
|
|
||||||
const decodedMessage = decryptChatMessage(encodedMessageObj.data, keyPair.privateKey, senderPublicKey, encodedMessageObj.reference)
|
const decodedMessage = decryptChatMessage(encodedMessageObj.data, keyPair.privateKey, senderPublicKey, encodedMessageObj.reference)
|
||||||
return { secretCode: decodedMessage };
|
return { secretCode: decodedMessage };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
@ -379,6 +637,46 @@ async function listenForChatMessage({ nodeBaseUrl, senderAddress, senderPublicKe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function listenForChatMessageForBuyOrder({ nodeBaseUrl, senderAddress, senderPublicKey, signature }) {
|
||||||
|
try {
|
||||||
|
let validApi = "";
|
||||||
|
const checkIfNodeBaseUrlIsAcceptable = apiEndpoints.find(
|
||||||
|
(item) => item === nodeBaseUrl
|
||||||
|
);
|
||||||
|
if (checkIfNodeBaseUrlIsAcceptable) {
|
||||||
|
validApi = checkIfNodeBaseUrlIsAcceptable;
|
||||||
|
} else {
|
||||||
|
validApi = await findUsableApi();
|
||||||
|
}
|
||||||
|
const wallet = await getSaveWallet();
|
||||||
|
const address = wallet.address0;
|
||||||
|
const before = Date.now() + 1200000
|
||||||
|
const after = Date.now()
|
||||||
|
const apiCall = `${validApi}/chat/messages?involving=${senderAddress}&involving=${address}&reverse=true&limit=1&before=${before}&after=${after}`;
|
||||||
|
const parsedMessageObj = await fetchMessagesForBuyOrders(apiCall, signature, senderPublicKey)
|
||||||
|
|
||||||
|
// const resKeyPair = await getKeyPair()
|
||||||
|
// const parsedData = JSON.parse(resKeyPair)
|
||||||
|
// const uint8PrivateKey = Base58.decode(parsedData.privateKey);
|
||||||
|
// const uint8PublicKey = Base58.decode(parsedData.publicKey);
|
||||||
|
// const keyPair = {
|
||||||
|
// privateKey: uint8PrivateKey,
|
||||||
|
// publicKey: uint8PublicKey
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const decodedMessage = decryptChatMessage(encodedMessageObj.data, keyPair.privateKey, senderPublicKey, encodedMessageObj.reference)
|
||||||
|
// const parsedMessage = JSON.parse(decodedMessage)
|
||||||
|
chrome.tabs.query({}, function (tabs) {
|
||||||
|
tabs.forEach(tab => {
|
||||||
|
chrome.tabs.sendMessage(tab.id, { type: "RESPONSE_FOR_TRADES", message: parsedMessageObj });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
throw new Error(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||||
if (request) {
|
if (request) {
|
||||||
switch (request.action) {
|
switch (request.action) {
|
||||||
@ -396,21 +694,21 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "getWalletInfo":
|
case "getWalletInfo":
|
||||||
|
|
||||||
getKeyPair().then(()=> {
|
getKeyPair().then(() => {
|
||||||
chrome.storage.local.get(["walletInfo"], (result) => {
|
chrome.storage.local.get(["walletInfo"], (result) => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
sendResponse({ error: chrome.runtime.lastError.message });
|
sendResponse({ error: chrome.runtime.lastError.message });
|
||||||
} else if (result.walletInfo) {
|
} else if (result.walletInfo) {
|
||||||
sendResponse({ walletInfo: result.walletInfo });
|
sendResponse({ walletInfo: result.walletInfo });
|
||||||
} else {
|
} else {
|
||||||
sendResponse({ error: "No wallet info found" });
|
sendResponse({ error: "No wallet info found" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).catch((error)=> {
|
}).catch((error) => {
|
||||||
sendResponse({ error: error.message });
|
sendResponse({ error: error.message });
|
||||||
})
|
})
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "validApi":
|
case "validApi":
|
||||||
findUsableApi()
|
findUsableApi()
|
||||||
@ -439,21 +737,21 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
console.error(error.message);
|
console.error(error.message);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "decryptWallet": {
|
case "decryptWallet": {
|
||||||
const { password, wallet } = request.payload;
|
const { password, wallet } = request.payload;
|
||||||
|
|
||||||
decryptWallet({
|
decryptWallet({
|
||||||
password, wallet, walletVersion
|
password, wallet, walletVersion
|
||||||
|
})
|
||||||
|
.then((hasDecrypted) => {
|
||||||
|
sendResponse(hasDecrypted);
|
||||||
})
|
})
|
||||||
.then((hasDecrypted) => {
|
.catch((error) => {
|
||||||
sendResponse(hasDecrypted);
|
sendResponse({ error: error?.message });
|
||||||
})
|
console.error(error.message);
|
||||||
.catch((error) => {
|
});
|
||||||
sendResponse({ error: error?.message });
|
}
|
||||||
console.error(error.message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "balance":
|
case "balance":
|
||||||
getBalanceInfo()
|
getBalanceInfo()
|
||||||
@ -464,6 +762,18 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
console.error(error.message);
|
console.error(error.message);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case "ltcBalance": {
|
||||||
|
getLTCBalance()
|
||||||
|
.then((balance) => {
|
||||||
|
sendResponse(balance);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "sendCoin":
|
case "sendCoin":
|
||||||
{
|
{
|
||||||
const { receiver, password, amount } = request.payload;
|
const { receiver, password, amount } = request.payload;
|
||||||
@ -600,7 +910,87 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "connection":
|
case "buyOrder": {
|
||||||
|
const { qortalAtAddress, hostname } = request.payload;
|
||||||
|
getTradeInfo(qortalAtAddress)
|
||||||
|
.then((crosschainAtInfo) => {
|
||||||
|
const popupUrl = chrome.runtime.getURL("index.html");
|
||||||
|
|
||||||
|
chrome.windows.getAll(
|
||||||
|
{ populate: true, windowTypes: ["popup"] },
|
||||||
|
(windows) => {
|
||||||
|
// Attempt to find an existing popup window that has a tab with the correct URL
|
||||||
|
const existingPopup = windows.find(
|
||||||
|
(w) =>
|
||||||
|
w.tabs &&
|
||||||
|
w.tabs.some(
|
||||||
|
(tab) => tab.url && tab.url.startsWith(popupUrl)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (existingPopup) {
|
||||||
|
// If the popup exists but is minimized or not focused, focus it
|
||||||
|
chrome.windows.update(existingPopup.id, {
|
||||||
|
focused: true,
|
||||||
|
state: "normal",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// No existing popup found, create a new one
|
||||||
|
chrome.system.display.getInfo((displays) => {
|
||||||
|
// Assuming the primary display is the first one (adjust logic as needed)
|
||||||
|
const primaryDisplay = displays[0];
|
||||||
|
const screenWidth = primaryDisplay.bounds.width;
|
||||||
|
const windowHeight = 500; // Your window height
|
||||||
|
const windowWidth = 400; // Your window width
|
||||||
|
|
||||||
|
// Calculate left position for the window to appear on the right of the screen
|
||||||
|
const leftPosition = screenWidth - windowWidth;
|
||||||
|
|
||||||
|
// Calculate top position for the window, adjust as desired
|
||||||
|
const topPosition =
|
||||||
|
(primaryDisplay.bounds.height - windowHeight) / 2;
|
||||||
|
|
||||||
|
chrome.windows.create({
|
||||||
|
url: chrome.runtime.getURL("index.html"),
|
||||||
|
type: "popup",
|
||||||
|
width: windowWidth,
|
||||||
|
height: windowHeight,
|
||||||
|
left: leftPosition,
|
||||||
|
top: 0,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const interactionId = Date.now().toString(); // Simple example; consider a better unique ID
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
action: "SET_COUNTDOWN",
|
||||||
|
payload: request.timeout ? 0.9 * request.timeout : 20,
|
||||||
|
});
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
action: "UPDATE_STATE_REQUEST_BUY_ORDER",
|
||||||
|
payload: {
|
||||||
|
hostname,
|
||||||
|
crosschainAtInfo,
|
||||||
|
interactionId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
// Store sendResponse callback with the interaction ID
|
||||||
|
pendingResponses.set(interactionId, sendResponse);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "connection": {
|
||||||
const { hostname } = request.payload;
|
const { hostname } = request.payload;
|
||||||
connection(hostname)
|
connection(hostname)
|
||||||
.then((isConnected) => {
|
.then((isConnected) => {
|
||||||
@ -678,6 +1068,8 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(error.message);
|
console.error(error.message);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "sendQort":
|
case "sendQort":
|
||||||
{
|
{
|
||||||
@ -809,6 +1201,36 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "buyOrderConfirmation": {
|
||||||
|
const { crosschainAtInfo, isDecline } = request.payload;
|
||||||
|
const interactionId2 = request.payload.interactionId;
|
||||||
|
// Retrieve the stored sendResponse callback
|
||||||
|
const originalSendResponse = pendingResponses.get(interactionId2);
|
||||||
|
|
||||||
|
if (originalSendResponse) {
|
||||||
|
if (isDecline) {
|
||||||
|
originalSendResponse({ error: "User has declined" });
|
||||||
|
sendResponse(false);
|
||||||
|
pendingResponses.delete(interactionId2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
createBuyOrderTx({ crosschainAtInfo })
|
||||||
|
.then((res) => {
|
||||||
|
sendResponse(true);
|
||||||
|
originalSendResponse(res);
|
||||||
|
pendingResponses.delete(interactionId2);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error.message);
|
||||||
|
sendResponse({ error: error.message });
|
||||||
|
// originalSendResponse({ error: error.message });
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "logout":
|
case "logout":
|
||||||
{
|
{
|
||||||
@ -817,11 +1239,11 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
// Handle error
|
// Handle error
|
||||||
console.error(chrome.runtime.lastError.message);
|
console.error(chrome.runtime.lastError.message);
|
||||||
} else {
|
} else {
|
||||||
chrome.tabs.query({}, function(tabs) {
|
chrome.tabs.query({}, function (tabs) {
|
||||||
tabs.forEach(tab => {
|
tabs.forEach(tab => {
|
||||||
chrome.tabs.sendMessage(tab.id, { type: "LOGOUT" });
|
chrome.tabs.sendMessage(tab.id, { type: "LOGOUT" });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// Data removed successfully
|
// Data removed successfully
|
||||||
sendResponse(true);
|
sendResponse(true);
|
||||||
}
|
}
|
||||||
|
145
src/transactions/ChatBase.ts
Normal file
145
src/transactions/ChatBase.ts
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { QORT_DECIMALS, TX_TYPES } from '../constants/constants'
|
||||||
|
import nacl from '../deps/nacl-fast'
|
||||||
|
import Base58 from '../deps/Base58'
|
||||||
|
import utils from '../utils/utils'
|
||||||
|
|
||||||
|
export default class ChatBase {
|
||||||
|
static get utils() {
|
||||||
|
return utils
|
||||||
|
}
|
||||||
|
|
||||||
|
static get nacl() {
|
||||||
|
return nacl
|
||||||
|
}
|
||||||
|
|
||||||
|
static get Base58() {
|
||||||
|
return Base58
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.fee = 0
|
||||||
|
this.groupID = 0
|
||||||
|
this.tests = [
|
||||||
|
() => {
|
||||||
|
if (!(this._type >= 1 && this._type in TX_TYPES)) {
|
||||||
|
return 'Invalid type: ' + this.type
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
if (this._fee < 0) {
|
||||||
|
return 'Invalid fee: ' + this._fee / QORT_DECIMALS
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
if (this._groupID < 0 || !Number.isInteger(this._groupID)) {
|
||||||
|
return 'Invalid groupID: ' + this._groupID
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
if (!(new Date(this._timestamp)).getTime() > 0) {
|
||||||
|
return 'Invalid timestamp: ' + this._timestamp
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
if (!(this._lastReference instanceof Uint8Array && this._lastReference.byteLength == 64)) {
|
||||||
|
return 'Invalid last reference: ' + this._lastReference
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
if (!(this._keyPair)) {
|
||||||
|
return 'keyPair must be specified'
|
||||||
|
}
|
||||||
|
if (!(this._keyPair.publicKey instanceof Uint8Array && this._keyPair.publicKey.byteLength === 32)) {
|
||||||
|
return 'Invalid publicKey'
|
||||||
|
}
|
||||||
|
if (!(this._keyPair.privateKey instanceof Uint8Array && this._keyPair.privateKey.byteLength === 64)) {
|
||||||
|
return 'Invalid privateKey'
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
set keyPair(keyPair) {
|
||||||
|
this._keyPair = keyPair
|
||||||
|
}
|
||||||
|
|
||||||
|
set type(type) {
|
||||||
|
this.typeText = TX_TYPES[type]
|
||||||
|
this._type = type
|
||||||
|
this._typeBytes = this.constructor.utils.int32ToBytes(this._type)
|
||||||
|
}
|
||||||
|
|
||||||
|
set groupID(groupID) {
|
||||||
|
this._groupID = groupID
|
||||||
|
this._groupIDBytes = this.constructor.utils.int32ToBytes(this._groupID)
|
||||||
|
}
|
||||||
|
|
||||||
|
set timestamp(timestamp) {
|
||||||
|
this._timestamp = timestamp
|
||||||
|
this._timestampBytes = this.constructor.utils.int64ToBytes(this._timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
set fee(fee) {
|
||||||
|
this._fee = fee * QORT_DECIMALS
|
||||||
|
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||||
|
}
|
||||||
|
|
||||||
|
set lastReference(lastReference) {
|
||||||
|
this._lastReference = lastReference instanceof Uint8Array ? lastReference : this.constructor.Base58.decode(lastReference)
|
||||||
|
}
|
||||||
|
|
||||||
|
get params() {
|
||||||
|
return [
|
||||||
|
this._typeBytes,
|
||||||
|
this._timestampBytes,
|
||||||
|
this._groupIDBytes,
|
||||||
|
this._lastReference,
|
||||||
|
this._keyPair.publicKey
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
get chatBytes() {
|
||||||
|
const isValid = this.validParams()
|
||||||
|
if (!isValid.valid) {
|
||||||
|
throw new Error(isValid.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = new Uint8Array()
|
||||||
|
|
||||||
|
this.params.forEach(item => {
|
||||||
|
result = this.constructor.utils.appendBuffer(result, item)
|
||||||
|
})
|
||||||
|
|
||||||
|
this._chatBytes = result
|
||||||
|
|
||||||
|
return this._chatBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
validParams() {
|
||||||
|
let finalResult = {
|
||||||
|
valid: true
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tests.some(test => {
|
||||||
|
const result = test()
|
||||||
|
if (result !== true) {
|
||||||
|
finalResult = {
|
||||||
|
valid: false,
|
||||||
|
message: result
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return finalResult
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
92
src/transactions/ChatTransaction.ts
Normal file
92
src/transactions/ChatTransaction.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import ChatBase from './ChatBase'
|
||||||
|
import nacl from '../deps/nacl-fast'
|
||||||
|
import ed2curve from '../deps/ed2curve'
|
||||||
|
import { Sha256 } from 'asmcrypto.js'
|
||||||
|
import { CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP } from '../constants/constants'
|
||||||
|
|
||||||
|
export default class ChatTransaction extends ChatBase {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.type = 18
|
||||||
|
this.fee = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
set recipientPublicKey(recipientPublicKey) {
|
||||||
|
this._base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? this.constructor.Base58.encode(recipientPublicKey) : recipientPublicKey
|
||||||
|
this._recipientPublicKey = this.constructor.Base58.decode(this._base58RecipientPublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
set proofOfWorkNonce(proofOfWorkNonce) {
|
||||||
|
this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
set recipient(recipient) {
|
||||||
|
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient)
|
||||||
|
this._hasReceipient = new Uint8Array(1)
|
||||||
|
this._hasReceipient[0] = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
set hasChatReference(hasChatReference) {
|
||||||
|
this._hasChatReference = new Uint8Array(1)
|
||||||
|
this._hasChatReference[0] = hasChatReference
|
||||||
|
}
|
||||||
|
|
||||||
|
set chatReference(chatReference) {
|
||||||
|
this._chatReference = chatReference instanceof Uint8Array ? chatReference : this.constructor.Base58.decode(chatReference)
|
||||||
|
}
|
||||||
|
|
||||||
|
set message(message) {
|
||||||
|
this.messageText = message;
|
||||||
|
this._message = this.constructor.utils.stringtoUTF8Array(message)
|
||||||
|
this._messageLength = this.constructor.utils.int32ToBytes(this._message.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
set isEncrypted(isEncrypted) {
|
||||||
|
this._isEncrypted = new Uint8Array(1)
|
||||||
|
this._isEncrypted[0] = isEncrypted
|
||||||
|
|
||||||
|
if (isEncrypted === 1) {
|
||||||
|
const convertedPrivateKey = ed2curve.convertSecretKey(this._keyPair.privateKey)
|
||||||
|
const convertedPublicKey = ed2curve.convertPublicKey(this._recipientPublicKey)
|
||||||
|
const sharedSecret = new Uint8Array(32)
|
||||||
|
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey)
|
||||||
|
|
||||||
|
this._chatEncryptionSeed = new Sha256().process(sharedSecret).finish().result
|
||||||
|
this._encryptedMessage = nacl.secretbox(this._message, this._lastReference.slice(0, 24), this._chatEncryptionSeed)
|
||||||
|
}
|
||||||
|
|
||||||
|
this._myMessage = isEncrypted === 1 ? this._encryptedMessage : this._message
|
||||||
|
this._myMessageLenth = isEncrypted === 1 ? this.constructor.utils.int32ToBytes(this._myMessage.length) : this._messageLength
|
||||||
|
}
|
||||||
|
|
||||||
|
set isText(isText) {
|
||||||
|
this._isText = new Uint8Array(1)
|
||||||
|
this._isText[0] = isText
|
||||||
|
}
|
||||||
|
|
||||||
|
get params() {
|
||||||
|
const params = super.params
|
||||||
|
params.push(
|
||||||
|
this._proofOfWorkNonce,
|
||||||
|
this._hasReceipient,
|
||||||
|
this._recipient,
|
||||||
|
this._myMessageLenth,
|
||||||
|
this._myMessage,
|
||||||
|
this._isEncrypted,
|
||||||
|
this._isText,
|
||||||
|
this._feeBytes
|
||||||
|
)
|
||||||
|
|
||||||
|
// After the feature trigger timestamp we need to include chat reference
|
||||||
|
if (new Date(this._timestamp).getTime() >= CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP) {
|
||||||
|
params.push(this._hasChatReference)
|
||||||
|
|
||||||
|
if (this._hasChatReference[0] == 1) {
|
||||||
|
params.push(this._chatReference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
}
|
39
src/transactions/signChat.ts
Normal file
39
src/transactions/signChat.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import nacl from '../deps/nacl-fast'
|
||||||
|
import utils from '../utils/utils'
|
||||||
|
|
||||||
|
export const signChat = (chatBytes, nonce, keyPair) => {
|
||||||
|
if (!chatBytes) {
|
||||||
|
throw new Error('Chat Bytes not defined')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nonce) {
|
||||||
|
throw new Error('Nonce not defined')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keyPair) {
|
||||||
|
throw new Error('keyPair not defined')
|
||||||
|
}
|
||||||
|
|
||||||
|
const _nonce = utils.int32ToBytes(nonce)
|
||||||
|
|
||||||
|
if (chatBytes.length === undefined) {
|
||||||
|
const _chatBytesBuffer = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; })
|
||||||
|
|
||||||
|
const chatBytesBuffer = new Uint8Array(_chatBytesBuffer)
|
||||||
|
chatBytesBuffer.set(_nonce, 112)
|
||||||
|
|
||||||
|
const signature = nacl.sign.detached(chatBytesBuffer, keyPair.privateKey)
|
||||||
|
|
||||||
|
return utils.appendBuffer(chatBytesBuffer, signature)
|
||||||
|
} else {
|
||||||
|
const chatBytesBuffer = new Uint8Array(chatBytes)
|
||||||
|
chatBytesBuffer.set(_nonce, 112)
|
||||||
|
|
||||||
|
const signature = nacl.sign.detached(chatBytesBuffer, keyPair.privateKey)
|
||||||
|
|
||||||
|
return utils.appendBuffer(chatBytesBuffer, signature)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,12 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
|
||||||
import PaymentTransaction from './PaymentTransaction.js'
|
import PaymentTransaction from './PaymentTransaction.js'
|
||||||
|
import ChatTransaction from './ChatTransaction.js'
|
||||||
|
|
||||||
|
|
||||||
export const transactionTypes = {
|
export const transactionTypes = {
|
||||||
2: PaymentTransaction,
|
2: PaymentTransaction,
|
||||||
|
18: ChatTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user