Skip to content

Commit

Permalink
electronJs example (MetaMask#192)
Browse files Browse the repository at this point in the history
* Adding a electronjs example

* Tweaking html

* Adding the missing qrcode dependency

* Updated the example to SDK 0.5.6 & converted to ts

* feat(electron): adds an example gif; updates package.json to be private in the electron example
  • Loading branch information
christopherferreira9 authored Aug 3, 2023
1 parent 2efc3e4 commit eb093ac
Show file tree
Hide file tree
Showing 11 changed files with 652 additions and 6 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,13 @@ MMSDK.connect()
```
![](./docs/demo_nodejs.gif)

### Electron
![](./docs/demo_electron.gif)

Follow example on:

- [nodejs example](./packages/examples/nodejs/README.md)
- [nodejs example](./packages/examples/nodejs/README.md)
- [electron example](./packages/examples/electronjs/README.md)

## SDK Options

Expand Down
Binary file added docs/demo_electron.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions packages/examples/electronjs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# electronjs example

### Install dependencies
```bash
yarn install
```

### Start
```bash
yarn start
```

If the installation does not work inside this repo run the following command after yarn install:
```bash
node node_modules/electron/install.js
```
87 changes: 87 additions & 0 deletions packages/examples/electronjs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MetaMask Electron</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300&display=swap" rel="stylesheet">
</head>
<style>
body {
font-family: 'Roboto', sans-serif;
}
.container {
text-align: center;
margin-top: 50px;
}
#accountContainer {
margin-top: 20px;
}
#buttonContainers {
margin-top: 20px;
}
.button {
min-width: 100px;
height: 50px;
border-radius: 5px;
border-color: transparent;

}
.button.primary {
background-color: teal;
color: white
}
.button.action {
background-color: coral;
color: white;
}
.button.danger {
background-color: red;
color: white
}
#response {
max-width: 80%;
overflow: auto;
}
#otpContainer {
position: fixed;
bottom: 30px;
width: 100%;
}
</style>
<body>
<div class="container">
<img src="https://raw.githubusercontent.com/MetaMask/brand-resources/cb6fd847f3a9cc5e231c749383c3898935e62eab/SVG/metamask-fox-wordmark-horizontal.svg" width="450" alt=''/>
<h1>Electron Test Dapp</h1>

<div id="buttonContainers">
<button class="button primary" id="connectButton">Connect</button>
<button class="button action" id="signButton">personal_sign</button>
<button class="button danger" id="terminateButton">Terminate</button>
</div>

<div id="accountContainer">
<b>Account:</b><div id="account"></div>
</div>

<div id="chainContainer">
<b>Chain:</b><div id="chain"></div>
</div>

<div id="responseContainer">
<b>Response:</b><div id="response"></div>
</div>
<canvas id="qrCode"></canvas>
<div id="otpContainer">
<h1>OTP:</h1>
<h1 id="otp"></h1>
</div>
</div>

</body>
<script>
require('./dist/src/sdk.js')
</script>
</html>
19 changes: 19 additions & 0 deletions packages/examples/electronjs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "electronjs-test-dapp",
"private": true,
"packageManager": "yarn@3.5.1",
"devDependencies": {
"@types/qrcode": "^1.5.1",
"electron": "^25.2.0"
},
"scripts": {
"build": "tsc",
"start": "npm run build && electron ./dist/src/main.js",
"allow-scripts": ""
},
"dependencies": {
"@metamask/sdk": "0.5.6",
"qrcode": "^1.5.3",
"typescript": "^5.1.6"
}
}
34 changes: 34 additions & 0 deletions packages/examples/electronjs/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { app, BrowserWindow } from 'electron';
import * as path from "path";

function createWindow () {
const win = new BrowserWindow({
width: 1200,
height: 1200,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
contextIsolation: false,
}
})

win.loadFile(path.join(__dirname, "../../index.html"))
.catch(err => console.log(err));
//win.webContents.openDevTools()
}

app.whenReady().then(() => {
createWindow()

app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
10 changes: 10 additions & 0 deletions packages/examples/electronjs/src/preload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector: string, text: string) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}

for (const type of ["chrome", "node", "electron"]) {
replaceText(`${type}-version`, process.versions[type as keyof NodeJS.ProcessVersions]);
}
})
6 changes: 6 additions & 0 deletions packages/examples/electronjs/src/renderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// No Node.js APIs are available in this process unless
// nodeIntegration is set to true in webPreferences.
// Use preload.js to selectively enable features
// needed in the renderer process.
151 changes: 151 additions & 0 deletions packages/examples/electronjs/src/sdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { MetaMaskSDK, SDKProvider } from '@metamask/sdk';

import QRCode from 'qrcode';
import { Buffer } from 'buffer';
import { existsSync } from 'fs';

// MetaMask SDK
const sdk = new MetaMaskSDK({
shouldShimWeb3: false,
storage: {
enabled: true,
},
dappMetadata: {
name: 'Electron Test Dapp',
url: 'https://metamask.io/sdk/',
},
modals: {
install: ({ link }) => {
QRCode.toCanvas(qrCodeDOM, link, (error: any) => {
if (error) console.error(error)
})
return {};
},
otp: () => {
return {
updateOTPValue: (otpValue) => {
if (otpValue !== '') {
otpDOM.innerText = otpValue;
}
},
};
},
},
});


// DOM Elements
const qrCodeDOM = document.getElementById('qrCode');
const otpDOM = document.getElementById('otp');
const signButtonDOM = document.getElementById('signButton');
const connectButtonDOM = document.getElementById('connectButton');
const terminateButtonDOM = document.getElementById('terminateButton');
const responseDOM = document.getElementById('response');
const accountsDOM = document.getElementById('account');
const chainDOM = document.getElementById('chain');

// App State
let account = ''
let chainId = ''
let response = ''
let ethereum: SDKProvider;


// SDK Functions

// Connect
const connect = async () => {
await ethereum.request({ method: 'eth_requestAccounts' })
.then((accounts) => {
account = accounts?.[0];
updateDOM(accountsDOM, account);
connectButtonDOM.textContent = 'Connected';
qrCodeDOM.style.display = 'none';
chainId = ethereum.chainId;
updateDOM(chainDOM, chainId);
signButtonDOM.style.display = 'inline';
})
.catch((error) => {
console.error(error);
});
};

// Sign
const sign = async () => {
const from = ethereum.selectedAddress;
const message = 'Hello World from the Electron Example dapp!';
const hexMessage = '0x' + Buffer.from(message, 'utf8').toString('hex');
ethereum.request({
method: 'personal_sign',
params: [hexMessage, from, 'Example password'],
}).then((result) => {
response = result as string;
updateDOM(responseDOM, result.toString());
console.log('sign', result);
}).catch((e) => console.log('sign ERR', e));
};

// Terminate
const terminate = () => {
sdk.terminate();
connectButtonDOM.textContent = 'Connect';
signButtonDOM.style.display = 'none';
accountsDOM.innerText = '';
chainDOM.innerText = '';
qrCodeDOM.innerText = '';
otpDOM.innerText = '';
responseDOM.innerText = '';
}


// Event listeners
connectButtonDOM.onclick = connect;
connectButtonDOM.addEventListener('click', connect);
signButtonDOM.addEventListener('click', sign);
terminateButtonDOM.addEventListener('click', terminate);


// Entry point
window.onload = async () => {
await sdk.init();
ethereum = sdk.getProvider();
setEventListeners();
if(hasSessionStored()) {
connectButtonDOM.innerText = 'Reconnecting...';
await connect();
}
}

const setEventListeners = () => {
ethereum.on('chainChanged', (chain: string) => {
console.log(`chainChanged ${chain}`);
chainId = chain;
updateDOM(chainDOM, chain);
});

ethereum.on('accountsChanged', (accounts: string[]) => {
if (accounts.length === 0) {
updateDOM(accountsDOM, 'Accounts disconnected!')
return;
}
console.log(`accountsChanged ${accounts}`);
account = accounts[0];
updateDOM(accountsDOM, accounts[0]);
});

ethereum.on('connect', () => {
qrCodeDOM.innerText = '';
if (account !== '') {
updateDOM(otpDOM, '');
}
});
};

// Helper functions
function updateDOM(domElement: HTMLElement, value: string){
domElement.innerText = value;
}

function hasSessionStored() {
return existsSync('.sdk-comm');
}
Loading

0 comments on commit eb093ac

Please sign in to comment.