diff --git a/public/background.js b/public/background.js
index 9f6f0543a..c0b775fe4 100644
--- a/public/background.js
+++ b/public/background.js
@@ -236,95 +236,95 @@ chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
})();
return true; // Keep the message channel open for async sendResponse
- } else if (request.action === 'submitTransaction') {
+ } else if (request.action === 'submitTransactionFromDashboard') {
(async function() {
- const senderUrl = sender.tab ? sender.tab.url : sender.url || null;
- console.log('Sender URL:', senderUrl);
- const domain = getBaseDomain(senderUrl);
- console.log('Domain:', domain);
+ // Retrieve the necessary data
+ const transactionData = request.transactionData;
+ const domain = request.domain;
+ const net = request.net;
+
+ // Validate transactionData
+ if (!transactionData || !transactionData.asset || !transactionData.recipientAddress || !transactionData.amount) {
+ sendResponse({ success: false, error: 'Invalid transaction data.' });
+ return;
+ }
+
+ // Retrieve the signer's keys and URL from storage
chrome.storage.local.get(['keys', 'connectedNets'], async function (result) {
const keys = result.keys || {};
const connectedNets = result.connectedNets || {};
- console.log('ConnectedNets:', connectedNets);
- const net = connectedNets[domain];
- console.log('Net for domain:', domain, 'is', net);
-
- if (keys[domain] && keys[domain][net]) {
- const { publicKey, privateKey, url, exportedKey } = keys[domain][net];
-
- try {
- // Import the key material from JWK format
- const keyMaterial = await crypto.subtle.importKey(
- 'jwk',
- exportedKey,
- { name: 'AES-GCM' },
- true,
- ['encrypt', 'decrypt']
- );
-
- const decryptedPublicKey = await decryptData(publicKey.ciphertext, publicKey.iv, keyMaterial);
- const decryptedPrivateKey = await decryptData(privateKey.ciphertext, privateKey.iv, keyMaterial);
- const decryptedUrl = await decryptData(url.ciphertext, url.iv, keyMaterial);
- // Check if required fields are defined
- if (!decryptedPublicKey || !decryptedPrivateKey || !request.recipient) {
- console.error('Missing required fields for transaction submission');
- sendResponse({ success: false, error: 'Missing required fields for transaction' });
- return;
- }
+ if (!connectedNets[domain] || connectedNets[domain] !== net) {
+ sendResponse({ success: false, error: 'Not connected to the specified net for this domain.' });
+ return;
+ }
- // Prepare asset data as a JSON string
- const assetData = JSON.stringify({
- data: request.data || {}
- });
+ if (!keys[domain] || !keys[domain][net]) {
+ sendResponse({ success: false, error: 'Keys not found for the specified domain and net.' });
+ return;
+ }
- // Construct the GraphQL mutation
- const mutation = `
- mutation {
- postTransaction(data: {
- operation: "CREATE",
- amount: ${parseInt(request.amount)},
- signerPublicKey: "${escapeGraphQLString(decryptedPublicKey)}",
- signerPrivateKey: "${escapeGraphQLString(decryptedPrivateKey)}",
- recipientPublicKey: "${escapeGraphQLString(request.recipient)}",
- asset: """${assetData}"""
- }) {
- id
- }
+ const { publicKey, privateKey, url, exportedKey } = keys[domain][net];
+
+ try {
+ // Import the key material from JWK format
+ const keyMaterial = await crypto.subtle.importKey(
+ 'jwk',
+ exportedKey,
+ { name: 'AES-GCM',
+ },
+ true,
+ ['encrypt', 'decrypt']
+ );
+
+ const decryptedPublicKey = await decryptData(publicKey.ciphertext, publicKey.iv, keyMaterial);
+ const decryptedPrivateKey = await decryptData(privateKey.ciphertext, privateKey.iv, keyMaterial);
+ const decryptedUrl = await decryptData(url.ciphertext, url.iv, keyMaterial);
+
+ // Prepare the asset data
+ const assetData = JSON.stringify(transactionData.asset);
+
+ // Construct the GraphQL mutation
+ const mutation = `
+ mutation {
+ postTransaction(data: {
+ operation: "CREATE",
+ amount: ${parseInt(transactionData.amount)},
+ signerPublicKey: "${escapeGraphQLString(decryptedPublicKey)}",
+ signerPrivateKey: "${escapeGraphQLString(decryptedPrivateKey)}",
+ recipientPublicKey: "${escapeGraphQLString(transactionData.recipientAddress)}",
+ asset: """${assetData}"""
+ }) {
+ id
}
- `;
-
- // Log the mutation for debugging
- console.log('Mutation:', mutation);
-
- const response = await fetch(decryptedUrl, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ query: mutation }),
- });
-
- if (!response.ok) {
- throw new Error(`Network response was not ok: ${response.statusText}`);
}
+ `;
+
+ // Send the mutation
+ const response = await fetch(decryptedUrl, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ query: mutation }),
+ });
- const resultData = await response.json();
- if (resultData.errors) {
- console.error('GraphQL errors:', resultData.errors);
- sendResponse({ success: false, errors: resultData.errors });
- } else {
- console.log('Transaction submitted successfully:', resultData.data);
- sendResponse({ success: true, data: resultData.data });
- }
- } catch (error) {
- console.error('Error submitting transaction:', error);
- sendResponse({ success: false, error: error.message });
+ if (!response.ok) {
+ throw new Error(`Network response was not ok: ${response.statusText}`);
}
- } else {
- console.error('No keys found for domain:', domain, 'and net:', net);
- console.log('Available keys:', keys);
- sendResponse({ error: "No keys found for domain and net" });
+
+ const resultData = await response.json();
+ if (resultData.errors) {
+ console.error('GraphQL errors:', resultData.errors);
+ sendResponse({ success: false, error: 'GraphQL errors occurred.', errors: resultData.errors });
+ } else {
+ console.log('Transaction submitted successfully:', resultData.data);
+ sendResponse({ success: true, data: resultData.data });
+ }
+
+ } catch (error) {
+ console.error('Error submitting transaction:', error);
+ sendResponse({ success: false, error: error.message });
}
});
})();
diff --git a/src/pages/Dashboard.jsx b/src/pages/Dashboard.jsx
index 3a378bdfc..caf28f1c6 100644
--- a/src/pages/Dashboard.jsx
+++ b/src/pages/Dashboard.jsx
@@ -11,8 +11,8 @@
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied. See the License for the
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+* OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
@@ -49,6 +49,15 @@ function Dashboard() {
const inputRef = useRef(null);
const navigate = useNavigate();
+ // New state variables for transaction data and handling
+ const [transactionData, setTransactionData] = useState(null);
+ const [transactionError, setTransactionError] = useState('');
+ const [showSuccessModal, setShowSuccessModal] = useState(false);
+ const [successResponse, setSuccessResponse] = useState(null);
+
+ // New state for copying transaction ID
+ const [isIdCopied, setIsIdCopied] = useState(false);
+
useEffect(() => {
console.log('publicKey in Dashboard:', publicKey);
console.log('privateKey in Dashboard:', privateKey);
@@ -109,7 +118,7 @@ function Dashboard() {
useEffect(() => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
- if (tabs.length > 0) {
+ if (tabs.length > 0 && tabs[0].url) {
const currentTab = tabs[0];
setTabId(currentTab.id);
@@ -123,7 +132,15 @@ function Dashboard() {
});
}
} else {
- setIsConnected(false);
+ // If no active tab or no URL, set domain to 'extension'
+ setDomain('extension');
+
+ // Ensure selectedNet is set before checking connection status
+ if (selectedNet) {
+ getDomainConnectionStatus('extension', selectedNet, (connected) => {
+ setIsConnected(connected);
+ });
+ }
}
});
}, [selectedNet]);
@@ -219,10 +236,6 @@ function Dashboard() {
return;
}
- // Log keys for debugging (Remove in production)
- console.log('Connecting with publicKey:', publicKey);
- console.log('Connecting with privateKey:', privateKey);
-
const newConnectionStatus = !isConnected;
setIsConnected(newConnectionStatus);
@@ -351,18 +364,34 @@ function Dashboard() {
}
};
- const [isJSONInvalid, setIsJSONInvalid] = useState(false);
-
- const showError = () => {
- setIsJSONInvalid(true);
- };
-
const handleFileUpload = (e) => {
const file = e.target.files[0];
if (file && file.type === 'application/json') {
setJsonFileName(file.name); // Show file name once uploaded
+
+ const reader = new FileReader();
+ reader.onload = (event) => {
+ try {
+ const json = JSON.parse(event.target.result);
+ // Validate JSON data
+ if (json.asset && json.recipientAddress && json.amount) {
+ setTransactionData(json);
+ setTransactionError(''); // Clear any previous error
+ } else {
+ setTransactionData(null);
+ setTransactionError('Invalid JSON format: Missing required fields.');
+ }
+ } catch (err) {
+ console.error('Error parsing JSON:', err);
+ setTransactionData(null);
+ setTransactionError('Invalid JSON format.');
+ }
+ };
+ reader.readAsText(file);
} else {
setJsonFileName(''); // Clear if the file is not JSON
+ setTransactionData(null);
+ setTransactionError('Please upload a JSON file.');
}
};
@@ -382,8 +411,30 @@ function Dashboard() {
const file = e.dataTransfer.files[0];
if (file && file.type === 'application/json') {
setJsonFileName(file.name);
+
+ const reader = new FileReader();
+ reader.onload = (event) => {
+ try {
+ const json = JSON.parse(event.target.result);
+ // Validate JSON data
+ if (json.asset && json.recipientAddress && json.amount) {
+ setTransactionData(json);
+ setTransactionError(''); // Clear any previous error
+ } else {
+ setTransactionData(null);
+ setTransactionError('Invalid JSON format: Missing required fields.');
+ }
+ } catch (err) {
+ console.error('Error parsing JSON:', err);
+ setTransactionData(null);
+ setTransactionError('Invalid JSON format.');
+ }
+ };
+ reader.readAsText(file);
} else {
setJsonFileName('');
+ setTransactionData(null);
+ setTransactionError('Please upload a JSON file.');
}
};
@@ -392,7 +443,51 @@ function Dashboard() {
};
const handleSubmit = () => {
- setJsonFileName(''); // Clear the file name on submit
+ if (!transactionData) {
+ setTransactionError('No valid transaction data found.');
+ return;
+ }
+ if (!isConnected) {
+ setTransactionError('Please connect to a net before submitting a transaction.');
+ return;
+ }
+
+ // Send transaction data to background script
+ chrome.runtime.sendMessage({
+ action: 'submitTransactionFromDashboard',
+ transactionData: transactionData,
+ domain: domain,
+ net: selectedNet,
+ }, (response) => {
+ if (response.success) {
+ setSuccessResponse(response.data);
+ setShowSuccessModal(true);
+ setTransactionError('');
+ setJsonFileName(''); // Clear the file name after successful submission
+ setTransactionData(null);
+ } else {
+ setTransactionError(response.error || 'Transaction submission failed.');
+ }
+ });
+ };
+
+ // New function to handle transaction ID click
+ const handleIdClick = () => {
+ try {
+ const transactionId = (successResponse && successResponse.postTransaction && successResponse.postTransaction.id) || '';
+ const tempInput = document.createElement('input');
+ tempInput.value = transactionId;
+ document.body.appendChild(tempInput);
+ tempInput.select();
+ document.execCommand('copy');
+ document.body.removeChild(tempInput);
+ setIsIdCopied(true);
+ setTimeout(() => {
+ setIsIdCopied(false);
+ }, 1500);
+ } catch (err) {
+ console.error('Unable to copy text: ', err);
+ }
};
return (
@@ -401,7 +496,7 @@ function Dashboard() {
No transaction ID found.
+ )} + +{transactionError}
}