Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ziga/gateway metamask connect button #1579

Merged
merged 9 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tools/walletextension/api/staticOG/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 1 addition & 4 deletions tools/walletextension/api/staticOG/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,10 @@

<h2>◠. Obscuro Gateway Demo! ◠.</h2>


<button class="btn btn-primary btn-lg btn-block mb-3" id="join">Join</button>
<button class="btn btn-primary btn-lg btn-block mb-3" id="addAccount" style="display: none">Add current account</button>
<button class="btn btn-primary btn-lg btn-block mb-3" id="addAllAccounts" style="display: none">Add all accounts from Metamask</button>
<button class="btn btn-primary btn-lg btn-block mb-3" id="revokeUserID">Revoke UserID</button>

<p id="status"></p>

<table id="accountsTable" border="1">
<thead>
<tr>
Expand Down
229 changes: 132 additions & 97 deletions tools/walletextension/api/staticOG/javascript.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ const idAddAccount = "addAccount";
const idAddAllAccounts = "addAllAccounts";
const idRevokeUserID = "revokeUserID";
const idStatus = "status";
const obscuroGatewayVersion = "v1"
const idAccountsTable = "accountsTable";
const idTableBody = "tableBody";
const obscuroGatewayVersion = "v1";
const pathJoin = obscuroGatewayVersion + "/join/";
const pathAuthenticate = obscuroGatewayVersion + "/authenticate/";
const pathQuery = obscuroGatewayVersion + "/query/";
Expand All @@ -20,6 +22,7 @@ const jsonHeaders = {
};

const metamaskPersonalSign = "personal_sign";
const obscuroChainIDHex = "0x" + obscuroChainIDDecimal.toString(16); // Convert to hexadecimal and prefix with '0x'

function isValidUserIDFormat(value) {
return typeof value === 'string' && value.length === 64;
Expand Down Expand Up @@ -50,6 +53,19 @@ async function fetchAndDisplayVersion() {
}
}


function getNetworkName(gatewayAddress) {
switch(gatewayAddress) {
case 'https://uat-testnet.obscu.ro/':
return 'Obscuro UAT-Testnet';
case 'https://dev-testnet.obscu.ro/':
return 'Obscuro Dev-Testnet';
default:
return 'Obscuro Testnet';
}
}


function getRPCFromUrl(gatewayAddress) {
// get the correct RPC endpoint for each network
switch(gatewayAddress) {
Expand All @@ -68,14 +84,13 @@ function getRPCFromUrl(gatewayAddress) {

async function addNetworkToMetaMask(ethereum, userID, chainIDDecimal) {
// add network to MetaMask
let chainIdHex = "0x" + chainIDDecimal.toString(16); // Convert to hexadecimal and prefix with '0x'
try {
await ethereum.request({
method: 'wallet_addEthereumChain',
params: [
{
chainId: chainIdHex,
chainName: 'Obscuro Testnet',
chainId: obscuroChainIDHex,
chainName: getNetworkName(obscuroGatewayAddress),
nativeCurrency: {
name: 'Sepolia Ether',
symbol: 'ETH',
Expand All @@ -95,7 +110,6 @@ async function addNetworkToMetaMask(ethereum, userID, chainIDDecimal) {

async function authenticateAccountWithObscuroGateway(ethereum, account, userID) {
const isAuthenticated = await accountIsAuthenticated(account, userID)

if (isAuthenticated) {
return "Account is already authenticated"
}
Expand Down Expand Up @@ -152,17 +166,20 @@ function getRandomIntAsString(min, max) {
return randomInt.toString();
}


async function getUserID() {
try {
return await provider.send('eth_getStorageAt', ["getUserID", getRandomIntAsString(0, 1000), null])
if (await isObscuroChain()) {
return await provider.send('eth_getStorageAt', ["getUserID", getRandomIntAsString(0, 1000), null])
} else {
return null
}
}catch (e) {
console.log(e)
return null;
}
}

async function connectAccount() {
async function connectAccounts() {
try {
return await window.ethereum.request({ method: 'eth_requestAccounts' });
} catch (error) {
Expand All @@ -172,6 +189,18 @@ async function connectAccount() {
}
}

async function isMetamaskConnected() {
let accounts;
try {
accounts = await provider.listAccounts()
return accounts.length > 0;

} catch (error) {
console.log("Unable to get accounts")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this return false ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is already returning false (after catch statement is executed)

}
return false
}

// Check if Metamask is available on mobile or as a plugin in browser
// (https://docs.metamask.io/wallet/how-to/integrate-with-mobile/)
function checkIfMetamaskIsLoaded() {
Expand Down Expand Up @@ -225,113 +254,125 @@ async function populateAccountsTable(document, tableBody, userID) {
}
}

async function isObscuroChain() {
let currentChain = await ethereum.request({ method: 'eth_chainId' });
return currentChain === obscuroChainIDHex
}

async function switchToObscuroNetwork() {
try {
await ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: obscuroChainIDHex }],
});
return 0
} catch (switchError) {
return switchError.code
}
return -1
}

const initialize = async () => {
const joinButton = document.getElementById(idJoin);
const addAccountButton = document.getElementById(idAddAccount);
const addAllAccountsButton = document.getElementById(idAddAllAccounts);
const revokeUserIDButton = document.getElementById(idRevokeUserID);
const statusArea = document.getElementById(idStatus);

const accountsTable = document.getElementById('accountsTable')
const tableBody = document.getElementById('tableBody');
const accountsTable = document.getElementById(idAccountsTable)
const tableBody = document.getElementById(idTableBody);
// getUserID from the gateway with getStorageAt method
let userID = await getUserID()


// load the current version
await fetchAndDisplayVersion();

// check if userID exists and has a correct type and length (is valid) and display either
// option to join or to add a new account to existing user
if (isValidUserIDFormat(userID)) {
joinButton.style.display = "none"
addAccountButton.style.display = "block"
addAllAccountsButton.style.display = "block"
revokeUserIDButton.style.display = "block"
accountsTable.style.display = "block"
await populateAccountsTable(document, tableBody, userID)
} else {
function displayOnlyJoin() {
joinButton.style.display = "block"
addAccountButton.style.display = "none"
revokeUserIDButton.style.display = "none"
accountsTable.style.display = "none"
}

joinButton.addEventListener(eventClick, async () => {
// join Obscuro Gateway
const joinResp = await fetch(
pathJoin, {
method: methodGet,
headers: jsonHeaders,
}
);
if (!joinResp.ok) {
statusArea.innerText = "Failed to join. \nError: " + joinResp
return
}

// save userID to the localStorage and hide button that enables users to join
userID = await joinResp.text();
async function displayConnectedAndJoinedSuccessfully() {
joinButton.style.display = "none"

// add Obscuro network to Metamask
let networkAdded = await addNetworkToMetaMask(ethereum, userID, obscuroChainIDDecimal)
if (!networkAdded) {
statusArea.innerText = "Failed to add network"
return
}
statusArea.innerText = "Successfully joined Obscuro Gateway";
// show users an option to add another account and revoke userID
addAccountButton.style.display = "block"
addAllAccountsButton.style.display = "block"
revokeUserIDButton.style.display = "block"
accountsTable.style.display = "block"
await populateAccountsTable(document, tableBody, userID)
})
}

addAccountButton.addEventListener(eventClick, async () => {
// check if we have userID and it is the correct length
if (!isValidUserIDFormat(userID)) {
statusArea.innerText = "\n Please join Obscuro network first"
joinButton.style.display = "block"
addAccountButton.style.display = "none"
async function displayCorrectScreenBasedOnMetamaskAndUserID() {
// check if we are on Obscuro Chain
if(await isObscuroChain()){
// check if we have valid userID in rpcURL
if (isValidUserIDFormat(userID)) {
return await displayConnectedAndJoinedSuccessfully()
}
}
return displayOnlyJoin()
}

await connectAccount()
// load the current version
await fetchAndDisplayVersion();

// Get an account and prompt user to sign joining with a selected account
const account = await provider.getSigner().getAddress();
if (account.length === 0) {
statusArea.innerText = "No MetaMask accounts found."
return
}
let authenticateAccountStatus = await authenticateAccountWithObscuroGateway(ethereum, account, userID)
//statusArea.innerText = "\n Authentication status: " + authenticateAccountStatus
accountsTable.style.display = "block"
await populateAccountsTable(document, tableBody, userID)
})
await displayCorrectScreenBasedOnMetamaskAndUserID()

addAllAccountsButton.addEventListener(eventClick, async () => {
// check if we have userID and it is the correct length
if (!isValidUserIDFormat(userID)) {
statusArea.innerText = "\n Please join Obscuro network first"
joinButton.style.display = "block"
addAccountButton.style.display = "none"
}
joinButton.addEventListener(eventClick, async () => {
// check if we are on an obscuro chain
if (await isObscuroChain()) {
userID = await getUserID()
if (!isValidUserIDFormat(userID)) {
statusArea.innerText = "Please remove existing Obscuro network from metamask and start again."
}
} else {
// we are not on an Obscuro network - try to switch
let switched = await switchToObscuroNetwork();
// error 4902 means that the chain does not exist
if (switched === 4902 || !isValidUserIDFormat(await getUserID())) {
// join the network
const joinResp = await fetch(
pathJoin, {
method: methodGet,
headers: jsonHeaders,
});
if (!joinResp.ok) {
console.log("Error joining Obscuro Gateway")
statusArea.innerText = "Error joining Obscuro Gateway. Please try again later."
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should something be logged to the console and/or user here ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added console log and message to user to try again later.

}
userID = await joinResp.text();

// add Obscuro network
await addNetworkToMetaMask(window.ethereum, userID)
}

await connectAccount()
// we have to check if user has accounts connected with metamask - and promt to connect if not
if (!await isMetamaskConnected()) {
await connectAccounts();
}

// Get an account and prompt user to sign joining with selected account
const accounts = await provider.listAccounts();
if (accounts.length === 0) {
statusArea.innerText = "No MetaMask accounts found."
return
}
// connect all accounts
// Get an accounts and prompt user to sign joining with a selected account
const accounts = await provider.listAccounts();
if (accounts.length === 0) {
statusArea.innerText = "No MetaMask accounts found."
return
}

userID = await getUserID();
for (const account of accounts) {
await authenticateAccountWithObscuroGateway(ethereum, account, userID)
accountsTable.style.display = "block"
await populateAccountsTable(document, tableBody, userID)
}

for (const account of accounts) {
let authenticateAccountStatus = await authenticateAccountWithObscuroGateway(ethereum, account, userID)
accountsTable.style.display = "block"
await populateAccountsTable(document, tableBody, userID)
// if accounts change we want to give user chance to add them to Obscuro
window.ethereum.on('accountsChanged', async function (accounts) {
if (isValidUserIDFormat(await getUserID())) {
userID = await getUserID();
for (const account of accounts) {
await authenticateAccountWithObscuroGateway(ethereum, account, userID)
accountsTable.style.display = "block"
await populateAccountsTable(document, tableBody, userID)
}
}
});

await displayConnectedAndJoinedSuccessfully()
}
})

Expand All @@ -341,17 +382,11 @@ const initialize = async () => {
await populateAccountsTable(document, tableBody, userID)

if (result) {
joinButton.style.display = "block";
revokeUserIDButton.style.display = "none";
addAllAccountsButton.style.display = "none";
statusArea.innerText = "Revoking UserID successful. Please remove current network from Metamask."
addAccountButton.style.display = "none";
accountsTable.style.display = "none"
displayOnlyJoin()
} else {
statusArea.innerText = "Revoking UserID failed";
}
})

}

window.addEventListener(eventDomLoaded, checkIfMetamaskIsLoaded);
Expand Down
Loading