This is an automated email from the ASF dual-hosted git repository.

apratim pushed a commit to branch main
in repository 
https://gitbox.apache.org/repos/asf/incubator-resilientdb-resvault.git


The following commit(s) were added to refs/heads/main by this push:
     new 0c5d1fc  Added smart contract deployment support
0c5d1fc is described below

commit 0c5d1fcb0b7fc968ab94755382c650b10561a3f0
Author: Apratim Shukla <apratimshuk...@gmail.com>
AuthorDate: Fri Nov 22 00:14:37 2024 -0800

    Added smart contract deployment support
    
    - ResVault now allows you to upload a solidity contract, with JSON 
configuration and deploy it.
    - In-built owner's address generation through public/private keys stored 
within ResVault.
    - Integrated with add address method and then execution of corresponding 
mutations.
    - Multiple nets support similar to KV service.
    - Consistent UI.
---
 .gitignore                                |   2 +
 package-lock.json                         |  11 +
 package.json                              |   1 +
 public/background.js                      | 170 +++++++++
 src/App.js                                |  10 +-
 src/context/GlobalContext.js              |  90 +++--
 src/css/App.css                           |   8 +
 src/pages/{Dashboard.jsx => Contract.jsx} | 569 +++++++++++++++++++-----------
 src/pages/Dashboard.jsx                   |  21 +-
 9 files changed, 650 insertions(+), 232 deletions(-)

diff --git a/.gitignore b/.gitignore
index 4d29575..5ce422f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,5 @@
 npm-debug.log*
 yarn-debug.log*
 yarn-error.log*
+
+build.zip
diff --git a/package-lock.json b/package-lock.json
index 3f9db0a..65376ef 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -33,6 +33,7 @@
         "crypto": "^1.0.1",
         "crypto-browserify": "^3.12.0",
         "crypto-js": "^4.1.1",
+        "js-sha3": "^0.9.3",
         "jssha": "^3.3.0",
         "mnemonic-seed-js": "^0.3.1",
         "moment": "^2.29.4",
@@ -15164,6 +15165,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/js-sha3": {
+      "version": "0.9.3",
+      "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.9.3.tgz";,
+      "integrity": 
"sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg=="
+    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz";,
@@ -37558,6 +37564,11 @@
       "resolved": 
"https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz";,
       "integrity": 
"sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g=="
     },
+    "js-sha3": {
+      "version": "0.9.3",
+      "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.9.3.tgz";,
+      "integrity": 
"sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg=="
+    },
     "js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz";,
diff --git a/package.json b/package.json
index 27359d2..822b2c4 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,7 @@
     "crypto": "^1.0.1",
     "crypto-browserify": "^3.12.0",
     "crypto-js": "^4.1.1",
+    "js-sha3": "^0.9.3",
     "jssha": "^3.3.0",
     "mnemonic-seed-js": "^0.3.1",
     "moment": "^2.29.4",
diff --git a/public/background.js b/public/background.js
index 0f09cf3..7f724cd 100644
--- a/public/background.js
+++ b/public/background.js
@@ -554,6 +554,176 @@ chrome.runtime.onMessage.addListener(function (request, 
sender, sendResponse) {
             });
         })();
 
+        return true; // Keep the message channel open for async sendResponse
+    } else if (request.action === 'deployContractChain') {
+        // Handler for deploying contract chain
+        (async function() {
+            const domain = request.domain;
+            const net = request.net;
+            const ownerAddress = request.ownerAddress;
+            const soliditySource = request.soliditySource;
+            const deployConfig = request.deployConfig; // Contains arguments 
and contract_name
+
+            // 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 || {};
+
+                if (!connectedNets[domain] || connectedNets[domain] !== net) {
+                    sendResponse({ success: false, error: 'Not connected to 
the specified net for this domain.' });
+                    return;
+                }
+
+                if (!keys[domain] || !keys[domain][net]) {
+                    sendResponse({ success: false, error: 'Keys not found for 
the specified domain and net.' });
+                    return;
+                }
+
+                const { 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 decryptedUrl = await decryptData(url.ciphertext, 
url.iv, keyMaterial);
+
+                    // 1. Perform addAddress mutation
+                    const addAddressMutation = `
+                    mutation {
+                      addAddress(
+                        config: "5 127.0.0.1 10005",
+                        address: "${escapeGraphQLString(ownerAddress)}",
+                        type: "data"
+                      )
+                    }
+                    `;
+
+                    const addAddressResponse = await fetch(decryptedUrl, {
+                        method: 'POST',
+                        headers: {
+                            'Content-Type': 'application/json',
+                        },
+                        body: JSON.stringify({ query: addAddressMutation }),
+                    });
+
+                    if (!addAddressResponse.ok) {
+                        throw new Error(`Network response was not ok: 
${addAddressResponse.statusText}`);
+                    }
+
+                    const addAddressResult = await addAddressResponse.json();
+                    if (addAddressResult.errors) {
+                        console.error('GraphQL errors in addAddress:', 
addAddressResult.errors);
+                        sendResponse({ success: false, error: 'Error in 
addAddress mutation.', errors: addAddressResult.errors });
+                        return;
+                    }
+
+                    // Check if addAddress was successful
+                    if (addAddressResult.data && 
addAddressResult.data.addAddress === "Address added successfully") {
+                        // 2. Perform compileContract mutation
+                        const escapedSoliditySource = 
escapeGraphQLString(soliditySource);
+
+                        const compileContractMutation = `
+                        mutation {
+                          compileContract(
+                            source: """${escapedSoliditySource}""",
+                            type: "data"
+                        )
+                        }
+                        `;
+
+                        const compileContractResponse = await 
fetch(decryptedUrl, {
+                            method: 'POST',
+                            headers: {
+                                'Content-Type': 'application/json',
+                            },
+                            body: JSON.stringify({ query: 
compileContractMutation }),
+                        });
+
+                        if (!compileContractResponse.ok) {
+                            throw new Error(`Network response was not ok: 
${compileContractResponse.statusText}`);
+                        }
+
+                        const compileContractResult = await 
compileContractResponse.json();
+                        if (compileContractResult.errors) {
+                            console.error('GraphQL errors in 
compileContract:', compileContractResult.errors);
+                            sendResponse({ success: false, error: 'Error in 
compileContract mutation.', errors: compileContractResult.errors });
+                            return;
+                        }
+
+                        // Extract the contract filename
+                        const contractFilename = 
compileContractResult.data.compileContract;
+                        if (!contractFilename) {
+                            sendResponse({ success: false, error: 'Failed to 
compile contract.' });
+                            return;
+                        }
+
+                        // 3. Perform deployContract mutation
+                        const { arguments: args, contract_name } = 
deployConfig;
+                        const deployContractMutation = `
+                        mutation {
+                          deployContract(
+                            config: "5 127.0.0.1 10005",
+                            contract: 
"${escapeGraphQLString(contractFilename)}",
+                            name: 
"/tmp/${escapeGraphQLString(contractFilename.replace('.json', 
'.sol'))}:${escapeGraphQLString(contract_name)}",
+                            arguments: "${escapeGraphQLString(args)}",
+                            owner: "${escapeGraphQLString(ownerAddress)}",
+                            type: "data"
+                          ){
+                            ownerAddress
+                            contractAddress
+                            contractName
+                          }
+                        }
+                        `;
+
+                        const deployContractResponse = await 
fetch(decryptedUrl, {
+                            method: 'POST',
+                            headers: {
+                                'Content-Type': 'application/json',
+                            },
+                            body: JSON.stringify({ query: 
deployContractMutation }),
+                        });
+
+                        if (!deployContractResponse.ok) {
+                            throw new Error(`Network response was not ok: 
${deployContractResponse.statusText}`);
+                        }
+
+                        const deployContractResult = await 
deployContractResponse.json();
+                        if (deployContractResult.errors) {
+                            console.error('GraphQL errors in deployContract:', 
deployContractResult.errors);
+                            sendResponse({ success: false, error: 'Error in 
deployContract mutation.', errors: deployContractResult.errors });
+                            return;
+                        }
+
+                        // Extract the contract address and return success
+                        if (deployContractResult.data && 
deployContractResult.data.deployContract && 
deployContractResult.data.deployContract.contractAddress) {
+                            const contractAddress = 
deployContractResult.data.deployContract.contractAddress;
+                            sendResponse({ success: true, contractAddress: 
contractAddress });
+                            return;
+                        } else {
+                            sendResponse({ success: false, error: 'Failed to 
deploy contract.' });
+                            return;
+                        }
+
+                    } else {
+                        sendResponse({ success: false, error: 'Failed to add 
address.' });
+                        return;
+                    }
+
+                } catch (error) {
+                    console.error('Error deploying contract chain:', error);
+                    sendResponse({ success: false, error: error.message });
+                }
+            });
+        })();
+
         return true; // Keep the message channel open for async sendResponse
     }
 });
\ No newline at end of file
diff --git a/src/App.js b/src/App.js
index 1223c1f..4fc7b1f 100644
--- a/src/App.js
+++ b/src/App.js
@@ -6,11 +6,12 @@ import SignUp from "./pages/SignUp";
 import Login from "./pages/Login";
 import Dashboard from "./pages/Dashboard";
 import Logs from "./pages/Logs";
+import Contract from "./pages/Contract";
 import { Routes, Route, Navigate } from 'react-router-dom';
 import { GlobalContext } from './context/GlobalContext';
 
 function App() {
-  const { isAuthenticated } = useContext(GlobalContext);
+  const { serviceMode, isAuthenticated } = useContext(GlobalContext);
 
   return (
     <Routes>
@@ -21,11 +22,16 @@ function App() {
           <Route path="/login" element={<Login />} />
           <Route path="*" element={<Navigate to="/" replace />} />
         </>
-      ) : (
+      ) : serviceMode === 'KV' ? (
         <>
           <Route path="/dashboard" element={<Dashboard />} />
           <Route path="*" element={<Navigate to="/dashboard" replace />} />
         </>
+      ) : (
+        <>
+          <Route path="/contract" element={<Contract />} />
+          <Route path="*" element={<Navigate to="/contract" replace />} />
+        </>
       )}
     </Routes>
   );
diff --git a/src/context/GlobalContext.js b/src/context/GlobalContext.js
index 98512cd..04e068c 100644
--- a/src/context/GlobalContext.js
+++ b/src/context/GlobalContext.js
@@ -1,25 +1,39 @@
 /*global chrome*/
 import React, { createContext, useState, useEffect } from 'react';
 import CryptoJS from 'crypto-js';
+import { keccak256 } from 'js-sha3';
 import nacl from 'tweetnacl';
 import Base58 from 'bs58';
+import { useNavigate } from 'react-router-dom';
 
 export const GlobalContext = createContext();
 
 export const GlobalProvider = ({ children }) => {
+  const [serviceMode, setServiceMode] = useState('KV'); // KV or Contract
   const [values, setValues] = useState({ password: '', showPassword: false });
   const [confirmValues, setConfirmValues] = useState({ password: '', 
showPassword: false });
   const [loginValues, setLoginValues] = useState({ password: '', showPassword: 
false });
   const [publicKey, setPublicKey] = useState('');
   const [privateKey, setPrivateKey] = useState('');
+  const [ownerAddress, setOwnerAddress] = useState(''); // To store the 
generated owner's address
   const [keyPairs, setKeyPairs] = useState([]);
   const [selectedKeyPairIndex, setSelectedKeyPairIndex] = useState(0);
   const [isAuthenticated, setIsAuthenticated] = useState(false);
   const [storedPassword, setStoredPassword] = useState('');
+
+  const navigate = useNavigate();
   
   // Alert state for modals
   const [alert, setAlert] = useState({ isOpen: false, message: '' });
 
+  // Generate owner's address
+  const generateOwnerAddress = (publicKey) => {
+    const decodedPublicKey = Base58.decode(publicKey);
+    const addressHash = keccak256(Buffer.from(decodedPublicKey));
+    const address = `0x${addressHash.slice(-40)}`;
+    return address;
+  };
+
   // Function to encrypt and store key pairs
   const saveKeyPairsToStorage = (keyPairs, password) => {
     const encryptedKeyPairs = CryptoJS.AES.encrypt(
@@ -122,6 +136,10 @@ export const GlobalProvider = ({ children }) => {
         setPrivateKey(updatedKeyPairs[newIndex].privateKey);
         saveSelectedKeyPairIndex(newIndex);
 
+        // Generate and set the ownerAddress
+        const ownerAddress = 
generateOwnerAddress(updatedKeyPairs[newIndex].publicKey);
+        setOwnerAddress(ownerAddress);
+
         // Update 'store' with the new key pair
         const encryptedPrivateKey = 
CryptoJS.AES.encrypt(updatedKeyPairs[newIndex].privateKey, password).toString();
         const hash = CryptoJS.SHA256(password).toString(CryptoJS.enc.Hex);
@@ -162,6 +180,7 @@ export const GlobalProvider = ({ children }) => {
     const keyPair = nacl.sign.keyPair();
     const newPublicKey = Base58.encode(keyPair.publicKey);
     const newPrivateKey = Base58.encode(keyPair.secretKey.slice(0, 32)); // 
Using the first 32 bytes as seed
+    const ownerAddress = generateOwnerAddress(newPublicKey);
     const newKeyPair = { publicKey: newPublicKey, privateKey: newPrivateKey };
 
     // Load existing key pairs
@@ -184,6 +203,7 @@ export const GlobalProvider = ({ children }) => {
       setKeyPairs(updatedKeyPairs);
       setPublicKey(newPublicKey);
       setPrivateKey(newPrivateKey);
+      setOwnerAddress(ownerAddress);
       const newIndex = updatedKeyPairs.length - 1;
       setSelectedKeyPairIndex(newIndex);
       saveSelectedKeyPairIndex(newIndex);
@@ -237,6 +257,10 @@ export const GlobalProvider = ({ children }) => {
             setPublicKey(updatedKeyPairs[0].publicKey);
             setPrivateKey(updatedKeyPairs[0].privateKey);
             saveSelectedKeyPairIndex(0);
+
+            // Generate and set the ownerAddress
+            const ownerAddress = 
generateOwnerAddress(updatedKeyPairs[0].publicKey);
+            setOwnerAddress(ownerAddress);
         }
 
         // Update 'store' with the new selected key pair
@@ -275,10 +299,19 @@ export const GlobalProvider = ({ children }) => {
                 setPublicKey(loadedKeyPairs[index].publicKey);
                 setPrivateKey(loadedKeyPairs[index].privateKey);
                 setSelectedKeyPairIndex(index);
+
+                // Generate and set the ownerAddress
+                const ownerAddress = 
generateOwnerAddress(loadedKeyPairs[index].publicKey);
+                setOwnerAddress(ownerAddress);
+
               } else if (loadedKeyPairs.length > 0) {
                 setPublicKey(loadedKeyPairs[0].publicKey);
                 setPrivateKey(loadedKeyPairs[0].privateKey);
                 setSelectedKeyPairIndex(0);
+
+                // Generate and set the ownerAddress
+                const ownerAddress = 
generateOwnerAddress(loadedKeyPairs[0].publicKey);
+                setOwnerAddress(ownerAddress);
               }
               setIsAuthenticated(true);
             });
@@ -300,6 +333,10 @@ export const GlobalProvider = ({ children }) => {
       setSelectedKeyPairIndex(index);
       saveSelectedKeyPairIndex(index);
 
+      // Generate and set the ownerAddress
+      const ownerAddress = generateOwnerAddress(keyPairs[index].publicKey);
+      setOwnerAddress(ownerAddress);
+
       const password = storedPassword;
       if (!password) {
         console.error('Password is not available');
@@ -320,33 +357,46 @@ export const GlobalProvider = ({ children }) => {
     }
   };
 
+  useEffect(() => {
+    // Retrieve the mode from storage when the app starts
+    chrome.storage.local.get(['serviceMode'], (result) => {
+      if (result.serviceMode) {
+        setServiceMode(result.serviceMode);
+        navigate(result.serviceMode === 'KV' ? '/dashboard' : '/contract');
+      }
+    });
+  }, []);
+
+  const toggleServiceMode = () => {
+    const newMode = serviceMode === 'KV' ? 'Contract' : 'KV';
+    setServiceMode(newMode);
+    chrome.storage.local.set({ serviceMode: newMode }, () => {
+      // Clear connections when mode changes
+      chrome.storage.local.remove(['connections'], () => {
+        navigate(newMode === 'KV' ? '/dashboard' : '/contract');
+      });
+    });
+  };
+
   return (
     <GlobalContext.Provider
       value={{
-        values,
-        setValues,
-        confirmValues,
-        setConfirmValues,
-        loginValues,
-        setLoginValues,
-        publicKey,
-        setPublicKey,
-        privateKey,
-        setPrivateKey,
-        keyPairs,
-        setKeyPairs,
+        values, setValues,
+        confirmValues, setConfirmValues,
+        loginValues, setLoginValues,
+        publicKey, setPublicKey,
+        privateKey, setPrivateKey,
+        keyPairs, setKeyPairs,
         generateKeyPair,
-        selectedKeyPairIndex,
-        setSelectedKeyPairIndex,
+        selectedKeyPairIndex, setSelectedKeyPairIndex,
         setSelectedKeyPair: setSelectedKeyPairFn,
-        isAuthenticated,
-        setIsAuthenticated,
-        storedPassword,
-        setStoredPassword,
+        isAuthenticated, setIsAuthenticated,
+        storedPassword, setStoredPassword,
         deleteKeyPair,
         appendKeyPairs,
-        alert, // For alert modal
-        setAlert, // For alert modal
+        alert, setAlert,
+        serviceMode, setServiceMode, toggleServiceMode,
+        ownerAddress, setOwnerAddress,
       }}
     >
       {children}
diff --git a/src/css/App.css b/src/css/App.css
index fd9fcd1..3007d8b 100644
--- a/src/css/App.css
+++ b/src/css/App.css
@@ -3179,9 +3179,17 @@ body.panel-closing .page, body.panel-closing 
.bottom-toolbar {
   width: 100%;
 }
 
+.file-upload-row {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+}
+
 .file-upload {
   user-select: none;
   cursor: pointer;
+  flex: 1;
+  margin: 0 5px;
 }
 
 .drag_box {
diff --git a/src/pages/Dashboard.jsx b/src/pages/Contract.jsx
similarity index 63%
copy from src/pages/Dashboard.jsx
copy to src/pages/Contract.jsx
index bb28209..fb40d06 100644
--- a/src/pages/Dashboard.jsx
+++ b/src/pages/Contract.jsx
@@ -34,8 +34,10 @@ import { faLock, faUnlock } from 
'@fortawesome/free-solid-svg-icons';
 import graphql from "../images/logos/graphql.png";
 import { GlobalContext } from '../context/GlobalContext';
 import { useNavigate } from 'react-router-dom';
+import { keccak256 } from 'js-sha3';
+import Base58 from 'bs58';
 
-function Dashboard() {
+function Contract() {
     const {
         publicKey,
         privateKey,
@@ -51,6 +53,10 @@ function Dashboard() {
         appendKeyPairs, 
         alert, // For alert modal
         setAlert, // For alert modal
+        serviceMode,
+        toggleServiceMode,
+        ownerAddress,
+        setOwnerAddress,
     } = useContext(GlobalContext);
 
     const [tabId, setTabId] = useState(null);
@@ -71,15 +77,21 @@ function Dashboard() {
     const keyPairFileInputRef = useRef(null);
     const navigate = useNavigate();
 
-    // 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 Variables for Deployment
+    const [solidityFileName, setSolidityFileName] = useState('');
+    const [solidityContent, setSolidityContent] = useState('');
+    const [deployJsonFileName, setDeployJsonFileName] = useState('');
+    const [deployJsonContent, setDeployJsonContent] = useState('');
+    const [deployError, setDeployError] = useState('');
+    const [showContractModal, setShowContractModal] = useState(false);
+    const [contractAddress, setContractAddress] = useState('');
+    const [copyMessage, setCopyMessage] = useState('');
+
+    // Add the missing state declaration
     const [showDeleteModal, setShowDeleteModal] = useState(false);
 
-    // State for copying transaction ID
-    const [isIdCopied, setIsIdCopied] = useState(false);
+    // State for copying Contract Address
+    const [isAddressCopied, setIsAddressCopied] = useState(false);
 
     const defaultOptions = {
         loop: true,
@@ -101,6 +113,14 @@ function Dashboard() {
         }
     };
 
+    // Function to generate owner's address
+    const generateOwnerAddress = (publicKey) => {
+        const decodedPublicKey = Base58.decode(publicKey);
+        const addressHash = keccak256(Buffer.from(decodedPublicKey));
+        const address = `0x${addressHash.slice(-40)}`;
+        return address;
+    };
+
     // Function to get full hostname from URL
     function getBaseDomain(url) {
         try {
@@ -181,6 +201,7 @@ function Dashboard() {
         setNets(storedNets);
     }, []);
 
+    // Update useEffect to set default URLs based on serviceMode
     useEffect(() => {
         // Fetch active net URL from storage
         chrome.storage.local.get(['activeNetUrl'], (result) => {
@@ -188,9 +209,9 @@ function Dashboard() {
             setCompleteUrl(result.activeNetUrl); // Use the full URL with 
protocol
 
             // Check if it's one of the known networks
-            if (result.activeNetUrl === 
'https://cloud.resilientdb.com/graphql') {
+            if (result.activeNetUrl === 
'https://cloud.resilientdb.com/graphql' || result.activeNetUrl === 
'https://contract.resilientdb.com/graphql') {
             setSelectedNet('ResilientDB Mainnet');
-            } else if (result.activeNetUrl === 
'http://localhost:8000/graphql') {
+            } else if (result.activeNetUrl === 'http://localhost:8000/graphql' 
|| result.activeNetUrl === 'http://localhost:8400/graphql') {
             setSelectedNet('ResilientDB Localnet');
             } else {
             // Custom URL case
@@ -205,11 +226,12 @@ function Dashboard() {
             }
         } else {
             // No active net URL, default to ResilientDB Mainnet
-            setCompleteUrl('https://cloud.resilientdb.com/graphql');
+            const defaultUrl = serviceMode === 'KV' ? 
'https://cloud.resilientdb.com/graphql' : 
'https://contract.resilientdb.com/graphql';
+            setCompleteUrl(defaultUrl);
             setSelectedNet('ResilientDB Mainnet'); // Ensure default network 
is selected
         }
         });
-    }, [nets]);
+    }, [nets, serviceMode]);
 
     useEffect(() => {
         if (domain && selectedNet) {
@@ -289,6 +311,7 @@ function Dashboard() {
         }
     };
 
+    // Update the switchNetwork function to use URLs based on serviceMode
     const switchNetwork = (value) => {
         if (value === 'Manage Nets') {
         setShowModal(true);
@@ -296,10 +319,10 @@ function Dashboard() {
         let newCompleteUrl = '';
         switch (value) {
             case 'ResilientDB Mainnet':
-            newCompleteUrl = 'https://cloud.resilientdb.com/graphql';
+            newCompleteUrl = serviceMode === 'KV' ? 
'https://cloud.resilientdb.com/graphql' : 
'https://contract.resilientdb.com/graphql';
             break;
             case 'ResilientDB Localnet':
-            newCompleteUrl = 'http://localhost:8000/graphql';
+            newCompleteUrl = serviceMode === 'KV' ? 
'http://localhost:8000/graphql' : 'http://localhost:8400/graphql';
             break;
             case 'Custom URL':
             if (customUrl) {
@@ -376,11 +399,11 @@ function Dashboard() {
         }
     };       
 
-    // Function to copy public key
-    const handleCopyPublicKey = () => {
+    // Function to copy owner address
+    const handleCopyOwnerAddress = () => {
         try {
         const tempInput = document.createElement('input');
-        tempInput.value = publicKey;
+        tempInput.value = ownerAddress;
         document.body.appendChild(tempInput);
         tempInput.select();
         document.execCommand('copy');
@@ -395,9 +418,10 @@ function Dashboard() {
         }
     };
 
-    // Function to download key pair as JSON
+    // Function to download key pair including owner address
     const handleDownloadKeyPair = () => {
         const keyPair = {
+        ownerAddress: ownerAddress,
         publicKey: publicKey,
         privateKey: privateKey,
         };
@@ -410,12 +434,16 @@ function Dashboard() {
         downloadAnchorNode.remove();
     };
 
-    // Function to download all key pairs as JSON
+    // Function to download all key pairs including owner addresses
     const handleDownloadAllKeyPairs = () => {
-        const allKeyPairs = keyPairs.map(({ publicKey, privateKey }) => ({
-        publicKey,
-        privateKey,
-        }));
+        const allKeyPairs = keyPairs.map(({ publicKey, privateKey }) => {
+        const ownerAddress = generateOwnerAddress(publicKey);
+        return {
+            ownerAddress,
+            publicKey,
+            privateKey,
+        };
+        });
         const dataStr = "data:text/json;charset=utf-8," + 
encodeURIComponent(JSON.stringify(allKeyPairs));
         const downloadAnchorNode = document.createElement('a');
         downloadAnchorNode.setAttribute("href", dataStr);
@@ -425,115 +453,148 @@ function Dashboard() {
         downloadAnchorNode.remove();
     };
 
-    const handleFileUpload = (e) => {
+    // New Handlers for Deployment
+    const handleSolidityFileUpload = (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.');
-                setAlert({ isOpen: true, message: 'Invalid JSON format: 
Missing required fields.' });
-            }
-            } catch (err) {
-            console.error('Error parsing JSON:', err);
-            setTransactionData(null);
-            setTransactionError('Invalid JSON format.');
-            setAlert({ isOpen: true, message: 'Invalid JSON format.' });
-            }
-        };
-        reader.readAsText(file);
+        if (file && file.name.endsWith('.sol')) {
+            const reader = new FileReader();
+            reader.onload = (event) => {
+                setSolidityContent(event.target.result);
+                setSolidityFileName(file.name); // Set after reading
+                setDeployError(''); // Reset error message
+            };
+            reader.readAsText(file);
         } else {
-        setJsonFileName(''); // Clear if the file is not JSON
-        setTransactionData(null);
-        setTransactionError('Please upload a JSON file.');
-        setAlert({ isOpen: true, message: 'Please upload a valid JSON file.' 
});
+            setSolidityFileName('');
+            setSolidityContent('');
+            setDeployError('Please upload a valid Solidity (.sol) file.');
+            if (solidityFileInputRef.current) {
+                solidityFileInputRef.current.value = '';
+            }
         }
     };
 
-    // Function to handle file upload for key pairs
-    const handleKeyPairFileUpload = (e) => {
+    const handleDeployJsonFileUpload = (e) => {
         const file = e.target.files[0];
         if (file && file.type === 'application/json') {
             const reader = new FileReader();
             reader.onload = (event) => {
                 try {
-                    const uploadedKeyPairs = JSON.parse(event.target.result);
-
-                    // Ensure the uploaded data is either an array or an object
-                    if (Array.isArray(uploadedKeyPairs)) {
-                        appendKeyPairs(uploadedKeyPairs);
-                        // After appending, the context sets the 
selectedKeyPairIndex to the last one
-                    } else if (uploadedKeyPairs.publicKey && 
uploadedKeyPairs.privateKey) {
-                        appendKeyPairs([uploadedKeyPairs]); // Wrap single key 
pair into an array
-                        // After appending, the context sets the 
selectedKeyPairIndex to the last one
+                    const json = JSON.parse(event.target.result);
+                    // Validate JSON data
+                    if (typeof json.arguments === 'string' && typeof 
json.contract_name === 'string') {
+                        setDeployJsonContent(json);
+                        setDeployError('');
+                        setDeployJsonFileName(file.name); // Set file name 
after validation
                     } else {
-                        console.error('Invalid JSON format for key pairs.');
-                        setAlert({ isOpen: true, message: 'Invalid JSON format 
for key pairs.' });
+                        setDeployJsonContent(null);
+                        setDeployError('Invalid JSON: Missing "arguments" and 
"contract_name"');
+                        if (deployJsonFileInputRef.current) {
+                            deployJsonFileInputRef.current.value = '';
+                        }
                     }
                 } catch (err) {
                     console.error('Error parsing JSON:', err);
-                    setAlert({ isOpen: true, message: 'Error parsing JSON 
file.' });
+                    setDeployJsonContent(null);
+                    setDeployError('Invalid JSON format.');
+                    if (deployJsonFileInputRef.current) {
+                        deployJsonFileInputRef.current.value = '';
+                    }
                 }
             };
             reader.readAsText(file);
         } else {
-            console.error('Please upload a valid JSON file.');
-            setAlert({ isOpen: true, message: 'Please upload a valid JSON 
file.' });
+            setDeployJsonFileName('');
+            setDeployJsonContent(null);
+            setDeployError('Please upload a valid JSON file.');
+            if (deployJsonFileInputRef.current) {
+                deployJsonFileInputRef.current.value = '';
+            }
         }
     };
 
-    const handleDragEnter = (e) => {
+    // New Handlers for Deployment Drag and Drop
+    const handleDeployDragEnter = (e) => {
         e.preventDefault();
         e.stopPropagation();
     };
 
-    const handleDragOver = (e) => {
+    const handleDeployDragOver = (e) => {
         e.preventDefault();
         e.stopPropagation();
     };
 
-    const handleDrop = (e) => {
+    const handleDeployDrop = (e) => {
         e.preventDefault();
         e.stopPropagation();
         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.');
-                setAlert({ isOpen: true, message: 'Invalid JSON format: 
Missing required fields.' });
-            }
-            } catch (err) {
-            console.error('Error parsing JSON:', err);
-            setTransactionData(null);
-            setTransactionError('Invalid JSON format.');
-            setAlert({ isOpen: true, message: 'Invalid JSON format.' });
+            const reader = new FileReader();
+            reader.onload = (event) => {
+                try {
+                    const json = JSON.parse(event.target.result);
+                    // Validate JSON data
+                    if (typeof json.arguments === 'string' && typeof 
json.contract_name === 'string') {
+                        setDeployJsonContent(json);
+                        setDeployError('');
+                        setDeployJsonFileName(file.name); // Set file name 
after validation
+                    } else {
+                        setDeployJsonContent(null);
+                        setDeployError('Invalid JSON format: "arguments" and 
"contract_name" are required.');
+                        if (deployJsonFileInputRef.current) {
+                            deployJsonFileInputRef.current.value = '';
+                        }
+                    }
+                } catch (err) {
+                    console.error('Error parsing JSON:', err);
+                    setDeployJsonContent(null);
+                    setDeployError('Invalid JSON format.');
+                    if (deployJsonFileInputRef.current) {
+                        deployJsonFileInputRef.current.value = '';
+                    }
+                }
+            };
+            reader.readAsText(file);
+        } else {
+            setDeployJsonFileName('');
+            setDeployJsonContent(null);
+            setDeployError('Please upload a valid JSON file.');
+            if (deployJsonFileInputRef.current) {
+                deployJsonFileInputRef.current.value = '';
             }
-        };
-        reader.readAsText(file);
+        }
+    };
+
+    // Handler functions for Solidity Drag and Drop
+    const handleSolidityDragEnter = (e) => {
+        e.preventDefault();
+        e.stopPropagation();
+    };
+
+    const handleSolidityDragOver = (e) => {
+        e.preventDefault();
+        e.stopPropagation();
+    };
+
+    const handleSolidityDrop = (e) => {
+        e.preventDefault();
+        e.stopPropagation();
+        const file = e.dataTransfer.files[0];
+        if (file && file.name.endsWith('.sol')) {
+            const reader = new FileReader();
+            reader.onload = (event) => {
+                setSolidityContent(event.target.result);
+                setSolidityFileName(file.name); // Set after reading
+                setDeployError(''); // Reset error message
+            };
+            reader.readAsText(file);
         } else {
-        setJsonFileName('');
-        setTransactionData(null);
-        setTransactionError('Please upload a JSON file.');
-        setAlert({ isOpen: true, message: 'Please upload a valid JSON file.' 
});
+            setSolidityFileName('');
+            setSolidityContent('');
+            setDeployError('Please upload a valid Solidity (.sol) file.');
+            if (solidityFileInputRef.current) {
+                solidityFileInputRef.current.value = '';
+            }
         }
     };
 
@@ -545,58 +606,73 @@ function Dashboard() {
         keyPairFileInputRef.current.click();
     };
 
-    const handleSubmit = () => {
-        if (!transactionData) {
-        setTransactionError('No valid transaction data found.');
-        setAlert({ isOpen: true, message: 'No valid transaction data found.' 
});
-        return;
+    // New Handlers for Deployment
+    const handleDeployFileClick = () => {
+        deployJsonFileInputRef.current.click();
+    };
+
+    const deployJsonFileInputRef = useRef(null);
+    const solidityFileInputRef = useRef(null);
+
+    // New Handler for Deployment
+    const handleDeploy = () => {
+        // Validate that both Solidity and JSON files are uploaded
+        if (!solidityContent || !deployJsonContent) {
+            setDeployError('Both Solidity contract and JSON configuration 
files are required.');
+            return;
+        }
+
+        // Ensure JSON has required fields
+        const { arguments: args, contract_name } = deployJsonContent;
+        if (!args || !contract_name) {
+            setDeployError('JSON file must contain "arguments" and 
"contract_name".');
+            return;
         }
+
         if (!isConnected) {
-        setTransactionError('Please connect to a net before submitting a 
transaction.');
-        setAlert({ isOpen: true, message: 'Please connect to a net before 
submitting a transaction.' });
-        return;
+            setDeployError('Please connect to a net before deploying a 
contract.');
+            return;
         }
 
-        // Send transaction data to background script
+        // Send deployment data to background script
         chrome.runtime.sendMessage({
-        action: 'submitTransactionFromDashboard',
-        transactionData: transactionData,
-        domain: domain,
-        net: selectedNet,
+            action: 'deployContractChain',
+            soliditySource: solidityContent,
+            deployConfig: {
+                arguments: args,
+                contract_name: contract_name
+            },
+            ownerAddress: ownerAddress,
+            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.');
-            setAlert({ isOpen: true, message: response.error || 'Transaction 
submission failed.' });
-        }
+            if (response.success) {
+                if (response.contractAddress) {
+                    setContractAddress(response.contractAddress);
+                    setShowContractModal(true);
+                    // Clear the uploaded files
+                    setSolidityFileName('');
+                    setSolidityContent('');
+                    setDeployJsonFileName('');
+                    setDeployJsonContent(null);
+                    setDeployError('');
+
+                    // Reset file input values
+                    if (solidityFileInputRef.current) {
+                        solidityFileInputRef.current.value = '';
+                    }
+                    if (deployJsonFileInputRef.current) {
+                        deployJsonFileInputRef.current.value = '';
+                    }
+                } else {
+                    setDeployError('Deployment succeeded but no contract 
address returned.');
+                }
+            } else {
+                setDeployError(response.error || 'Contract deployment 
failed.');
+            }
         });
     };
 
-    // 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) {
-        setAlert({ isOpen: true, message: 'Unable to copy transaction ID.' });
-        console.error('Unable to copy text: ', err);
-        }
-    };
-
     // Function to handle favicon load error
     const handleFaviconError = () => {
         setFaviconUrl(''); // This will trigger the globe icon to display
@@ -634,6 +710,54 @@ function Dashboard() {
         setAlert({ isOpen: false, message: '' });
     };
 
+    // Handler function for uploading key pairs
+    const handleKeyPairFileUpload = (e) => {
+        const file = e.target.files[0];
+        if (file && file.type === 'application/json') {
+            const reader = new FileReader();
+            reader.onload = (event) => {
+                try {
+                    const json = JSON.parse(event.target.result);
+                    // Assume json is an array of keyPairs or a single keyPair
+                    if (Array.isArray(json)) {
+                        appendKeyPairs(json);
+                        setAlert({ isOpen: true, message: 'Key pairs uploaded 
successfully.' });
+                    } else if (json.publicKey && json.privateKey) {
+                        appendKeyPairs([json]);
+                        setAlert({ isOpen: true, message: 'Key pair uploaded 
successfully.' });
+                    } else {
+                        setAlert({ isOpen: true, message: 'Invalid JSON format 
for key pair.' });
+                    }
+                } catch (err) {
+                    console.error('Error parsing key pair JSON:', err);
+                    setAlert({ isOpen: true, message: 'Invalid JSON format for 
key pair.' });
+                }
+            };
+            reader.readAsText(file);
+        } else {
+            setAlert({ isOpen: true, message: 'Please upload a valid JSON 
file.' });
+        }
+    };
+
+    const handleAddressClick = () => {
+        try {
+        const address = contractAddress;
+        const tempInput = document.createElement('input');
+        tempInput.value = address;
+        document.body.appendChild(tempInput);
+        tempInput.select();
+        document.execCommand('copy');
+        document.body.removeChild(tempInput);
+        setIsAddressCopied(true);
+        setTimeout(() => {
+            setIsAddressCopied(false);
+        }, 1500);
+        } catch (err) {
+        setDeployError('Unable to copy contract address.');
+        console.error('Unable to copy text: ', err);
+        }
+    };
+
     return (
         <>
         <div className="lottie-background">
@@ -646,7 +770,9 @@ function Dashboard() {
                 Res<strong>Vault</strong>
                 </div>
                 <div className="badge-container">
-                <span className="badge">KV Service</span>
+                <span className="badge" onClick={toggleServiceMode}>
+                    {serviceMode === 'Contract' ? 'Smart Contract' : 
'Key-Value'}
+                </span>
                 </div>
                 <div className="header__icon open-panel">
                 <button
@@ -716,40 +842,6 @@ function Dashboard() {
             </div>
             )}
 
-            {showSuccessModal && (
-            <div className="overlay">
-                <div className="modal">
-                <div className="modal-content">
-                    <h2>Transaction Submitted Successfully!</h2>
-                    {/* Extract transaction ID */}
-                    {successResponse && successResponse.postTransaction && 
successResponse.postTransaction.id ? (
-                    <div className="fieldset">
-                        <div className="radio-option radio-option--full">
-                            <input
-                            type="radio"
-                            name="transactionId"
-                            id="txId"
-                            value={successResponse.postTransaction.id}
-                            checked
-                            readOnly
-                            onClick={handleIdClick}
-                            />
-                            <label htmlFor="txId">
-                            <span>{isIdCopied ? 'Copied' : 
`${successResponse.postTransaction.id.slice(0, 
5)}...${successResponse.postTransaction.id.slice(-5)}`}</span>
-                            </label>
-                        </div>
-                    </div>
-                    ) : (
-                    <p>No transaction ID found.</p>
-                    )}
-                    <button onClick={() => setShowSuccessModal(false)} 
className="button-close" title="Close Modal">
-                    Close
-                    </button>
-                </div>
-                </div>
-            </div>
-            )}
-
             {/* Alert Modal */}
             {alert.isOpen && (
                 <div className="overlay">
@@ -767,6 +859,37 @@ function Dashboard() {
                 </div>
             )}
 
+            {/* Contract Address Modal */}
+            {showContractModal && (
+                <div className="overlay">
+                    <div className="modal">
+                        <div className="modal-content">
+                            <h2>Contract Deployed Successfully!</h2>
+                            <p>Contract Address:</p>
+                            <div className="fieldset">
+                                <div className="radio-option 
radio-option--full">
+                                    <input
+                                    type="radio"
+                                    name="contractAddress"
+                                    id="contractAddress"
+                                    value={contractAddress}
+                                    checked
+                                    readOnly
+                                    onClick={handleAddressClick}
+                                    />
+                                    <label htmlFor="contractAddress">
+                                    <span>{isAddressCopied ? 'Copied' : 
`${contractAddress.slice(0, 5)}...${contractAddress.slice(-5)}`}</span>
+                                    </label>
+                                </div>
+                            </div>
+                            <button onClick={() => 
setShowContractModal(false)} className="button-close" title="Close Modal">
+                                Close
+                            </button>
+                        </div>
+                    </div>
+                </div>
+            )}
+
             <div className="page__content page__content--with-header 
page__content--with-bottom-nav">
             <h2 className="page__title">Dashboard</h2>
 
@@ -809,28 +932,58 @@ function Dashboard() {
                 )}
                 </div>
 
-                <div className="file-upload">
-                    <div
-                    className={`drag_box_outline ${jsonFileName ? 
'file-uploaded' : ''}`}
-                    onDragEnter={handleDragEnter}
-                    onDragOver={handleDragOver}
-                    onDrop={handleDrop}
-                    onClick={handleFileClick}
-                    >
-                    <input
-                        type="file"
-                        ref={fileInputRef}
-                        style={{ display: 'none' }}
-                        accept="application/json"
-                        onChange={handleFileUpload}
-                    />
-                    {jsonFileName ? (
-                        <span className="filename">{jsonFileName} 
uploaded</span>
-                    ) : (
-                        <span className="filename">Click to Upload JSON 
File</span>
-                    )}
+                {/* Deploy Contract Section */}
+                <div className="deploy-section">
+                    <div className="file-upload-row">
+                        {/* Solidity Contract Upload */}
+                        <div className="file-upload">
+                            <div
+                                className={`drag_box_outline 
${solidityFileName ? 'file-uploaded' : ''}`}
+                                onDragEnter={handleSolidityDragEnter}
+                                onDragOver={handleSolidityDragOver}
+                                onDrop={handleSolidityDrop}
+                                onClick={() => 
solidityFileInputRef.current.click()}
+                            >
+                                <input
+                                    type="file"
+                                    ref={solidityFileInputRef}
+                                    style={{ display: 'none' }}
+                                    accept=".sol"
+                                    onChange={handleSolidityFileUpload}
+                                />
+                                {solidityFileName ? (
+                                    <span 
className="filename">{solidityFileName} uploaded</span>
+                                ) : (
+                                    <span className="filename">Contract 
(.sol)</span>
+                                )}
+                            </div>
+                        </div>
+
+                        {/* JSON Configuration Upload */}
+                        <div className="file-upload">
+                            <div
+                                className={`drag_box_outline 
${deployJsonFileName ? 'file-uploaded' : ''}`}
+                                onDragEnter={handleDeployDragEnter}
+                                onDragOver={handleDeployDragOver}
+                                onDrop={handleDeployDrop}
+                                onClick={() => 
deployJsonFileInputRef.current.click()}
+                            >
+                                <input
+                                    type="file"
+                                    ref={deployJsonFileInputRef}
+                                    style={{ display: 'none' }}
+                                    accept="application/json"
+                                    onChange={handleDeployJsonFileUpload}
+                                />
+                                {deployJsonFileName ? (
+                                    <span 
className="filename">{deployJsonFileName} uploaded</span>
+                                ) : (
+                                    <span className="filename">Configuration 
(.json)</span>
+                                )}
+                            </div>
+                        </div>
                     </div>
-                    {transactionError && <p 
className="error-message">{transactionError}</p>}
+                    {deployError && <p 
className="error-message">{deployError}</p>}
                 </div>
             </div>
 
@@ -845,11 +998,14 @@ function Dashboard() {
                             onChange={(e) => 
switchKeyPair(Number(e.target.value))}
                             className="select"
                             >
-                            {keyPairs.map((keyPair, index) => (
+                            {keyPairs.map((keyPair, index) => {
+                                const ownerAddr = 
generateOwnerAddress(keyPair.publicKey);
+                                return (
                                 <option key={index} value={index}>
-                                {`${keyPair.publicKey.slice(0, 
4)}...${keyPair.publicKey.slice(-4)}`}
+                                    {`${ownerAddr.slice(0, 
4)}...${ownerAddr.slice(-4)}`}
                                 </option>
-                            ))}
+                                );
+                            })}
                             </select>
                             <i className="fas fa-chevron-down"></i>
                         </div>
@@ -859,7 +1015,7 @@ function Dashboard() {
                                 <DeleteIcon style={{ color: 'white' }} />
                             </button>
                             )}
-                            <button onClick={handleCopyPublicKey} 
className="icon-button" title="Copy Public Key">
+                            <button onClick={handleCopyOwnerAddress} 
className="icon-button" title="Copy Owner Address">
                                 <ContentCopyIcon style={{ color: isCopied ? 
'grey' : 'white' }} />
                             </button>
                             <button onClick={handleDownloadKeyPair} 
className="icon-button" title="Download Key Pair">
@@ -916,9 +1072,16 @@ function Dashboard() {
                 </div>
             )}
 
-            <button className="button button--full button--main open-popup" 
onClick={handleSubmit} title="Submit Transaction">
-                Submit
+            {/* Deploy Button */}
+            <button
+                className="button button--full button--main open-popup"
+                onClick={handleDeploy}
+                title="Deploy Contract"
+                disabled={!solidityContent || !deployJsonContent || 
!isConnected}
+            >
+                Deploy
             </button>
+
             <p className="bottom-navigation" style={{ backgroundColor: 
'transparent', display: 'flex', justifyContent: 'center', textShadow: '1px 1px 
1px rgba(0, 0, 0, 0.3)', color: 'rgb(255, 255, 255, 0.5)', fontSize: '9px' }}>
                 ResVault v{versionData.version}
             </p>
@@ -929,4 +1092,4 @@ function Dashboard() {
 
 }
 
-export default Dashboard;
\ No newline at end of file
+export default Contract;
\ No newline at end of file
diff --git a/src/pages/Dashboard.jsx b/src/pages/Dashboard.jsx
index bb28209..adfedcb 100644
--- a/src/pages/Dashboard.jsx
+++ b/src/pages/Dashboard.jsx
@@ -51,6 +51,8 @@ function Dashboard() {
         appendKeyPairs, 
         alert, // For alert modal
         setAlert, // For alert modal
+        serviceMode,
+        toggleServiceMode,
     } = useContext(GlobalContext);
 
     const [tabId, setTabId] = useState(null);
@@ -181,6 +183,7 @@ function Dashboard() {
         setNets(storedNets);
     }, []);
 
+    // Update useEffect to set default URLs based on serviceMode
     useEffect(() => {
         // Fetch active net URL from storage
         chrome.storage.local.get(['activeNetUrl'], (result) => {
@@ -188,9 +191,9 @@ function Dashboard() {
             setCompleteUrl(result.activeNetUrl); // Use the full URL with 
protocol
 
             // Check if it's one of the known networks
-            if (result.activeNetUrl === 
'https://cloud.resilientdb.com/graphql') {
+            if (result.activeNetUrl === 
'https://cloud.resilientdb.com/graphql' || result.activeNetUrl === 
'https://contract.resilientdb.com/graphql') {
             setSelectedNet('ResilientDB Mainnet');
-            } else if (result.activeNetUrl === 
'http://localhost:8000/graphql') {
+            } else if (result.activeNetUrl === 'http://localhost:8000/graphql' 
|| result.activeNetUrl === 'http://localhost:8400/graphql') {
             setSelectedNet('ResilientDB Localnet');
             } else {
             // Custom URL case
@@ -205,11 +208,12 @@ function Dashboard() {
             }
         } else {
             // No active net URL, default to ResilientDB Mainnet
-            setCompleteUrl('https://cloud.resilientdb.com/graphql');
+            const defaultUrl = serviceMode === 'KV' ? 
'https://cloud.resilientdb.com/graphql' : 
'https://contract.resilientdb.com/graphql';
+            setCompleteUrl(defaultUrl);
             setSelectedNet('ResilientDB Mainnet'); // Ensure default network 
is selected
         }
         });
-    }, [nets]);
+    }, [nets, serviceMode]);
 
     useEffect(() => {
         if (domain && selectedNet) {
@@ -289,6 +293,7 @@ function Dashboard() {
         }
     };
 
+    // Update the switchNetwork function to use URLs based on serviceMode
     const switchNetwork = (value) => {
         if (value === 'Manage Nets') {
         setShowModal(true);
@@ -296,10 +301,10 @@ function Dashboard() {
         let newCompleteUrl = '';
         switch (value) {
             case 'ResilientDB Mainnet':
-            newCompleteUrl = 'https://cloud.resilientdb.com/graphql';
+            newCompleteUrl = serviceMode === 'KV' ? 
'https://cloud.resilientdb.com/graphql' : 
'https://contract.resilientdb.com/graphql';
             break;
             case 'ResilientDB Localnet':
-            newCompleteUrl = 'http://localhost:8000/graphql';
+            newCompleteUrl = serviceMode === 'KV' ? 
'http://localhost:8000/graphql' : 'http://localhost:8400/graphql';
             break;
             case 'Custom URL':
             if (customUrl) {
@@ -646,7 +651,9 @@ function Dashboard() {
                 Res<strong>Vault</strong>
                 </div>
                 <div className="badge-container">
-                <span className="badge">KV Service</span>
+                <span className="badge" onClick={toggleServiceMode}>
+                    {serviceMode === 'KV' ? 'Key-Value' : 'Smart Contract'}
+                </span>
                 </div>
                 <div className="header__icon open-panel">
                 <button

Reply via email to