Initial commit
This commit is contained in:
commit
18d1a02e98
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules/
|
2
dist/bundle.js
vendored
Normal file
2
dist/bundle.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1291
dist/bundle.js.LICENSE.txt
vendored
Normal file
1291
dist/bundle.js.LICENSE.txt
vendored
Normal file
File diff suppressed because it is too large
Load Diff
21
index.html
Normal file
21
index.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>ZKL Roadhog Demo</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="dist/bundle.js"></script>
|
||||
<script>
|
||||
window.addEventListener('load', function () {
|
||||
document.getElementById('metamask').disabled = false;
|
||||
document.getElementById('phantom').disabled = false;
|
||||
});
|
||||
</script>
|
||||
<h1>ZKL Roadhog Demo</h1>
|
||||
<button disabled id="metamask" onclick="signIn('ethereum')">sign in with metamask</button>
|
||||
<button disabled id="phantom" onclick="signIn('solana')">sign in with solana</button>
|
||||
</body>
|
||||
|
||||
</html>
|
35
index.js
Normal file
35
index.js
Normal file
@ -0,0 +1,35 @@
|
||||
import { signIn as _signIn } from './roadhog.js';
|
||||
|
||||
const endpoint = "http://localhost:3000";
|
||||
|
||||
async function signIn(type) {
|
||||
try {
|
||||
const result = await _signIn(type);
|
||||
if (result.success) {
|
||||
console.log('Successfully signed in with', type);
|
||||
const b = document.createElement('button');
|
||||
b.innerText = 'Click to access protected';
|
||||
b.setAttribute('onclick', 'fetchProtected()');
|
||||
document.body.appendChild(b);
|
||||
} else {
|
||||
console.error('Sign-in failed:', result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Sign-in error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function signOff() {
|
||||
|
||||
}
|
||||
|
||||
window.signIn = signIn;
|
||||
window.signOff = signOff;
|
||||
|
||||
function init() {
|
||||
console.log('start');
|
||||
if (!window.ethereum) console.log('ethereum not detected');
|
||||
if (!window.solana) console.log('solana not detected');
|
||||
}
|
||||
|
||||
window.addEventListener('load', init);
|
13
package.json
Normal file
13
package.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"webpack": "^5.95.0",
|
||||
"webpack-cli": "^5.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@solana/web3.js": "^1.95.3",
|
||||
"bs58": "^6.0.0",
|
||||
"ethers": "^6.13.3",
|
||||
"siwe": "^2.3.2"
|
||||
}
|
||||
}
|
1502
pnpm-lock.yaml
generated
Normal file
1502
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
88
roadhog.js
Normal file
88
roadhog.js
Normal file
@ -0,0 +1,88 @@
|
||||
import { SiweMessage } from 'siwe';
|
||||
import { BrowserProvider, JsonRpcSigner } from 'ethers';
|
||||
import * as solanaWeb3 from '@solana/web3.js';
|
||||
import bs58 from 'bs58';
|
||||
|
||||
const endpoint = 'http://localhost:3000';
|
||||
|
||||
export async function signIn(type) {
|
||||
let address, signature, message;
|
||||
|
||||
if (type === 'ethereum') {
|
||||
await window.ethereum.request({ method: 'eth_requestAccounts' });
|
||||
const provider = new BrowserProvider(window.ethereum);
|
||||
const signer = await provider.getSigner();
|
||||
address = await signer.getAddress();
|
||||
|
||||
const nonceResponse = await fetch(`${endpoint}/auth/nonce?address=${address}&type=ethereum`);
|
||||
const { nonce } = await nonceResponse.json();
|
||||
|
||||
const siweMessage = new SiweMessage({
|
||||
domain: window.location.host,
|
||||
address: address,
|
||||
statement: 'Sign in with Ethereum to zk-Lokomotive.',
|
||||
uri: window.location.origin,
|
||||
version: '1',
|
||||
chainId: 1,
|
||||
nonce: nonce
|
||||
});
|
||||
|
||||
message = siweMessage.prepareMessage();
|
||||
signature = await signer.signMessage(message);
|
||||
} else if (type === 'solana') {
|
||||
const provider = window.solana;
|
||||
await provider.connect();
|
||||
address = provider.publicKey.toString();
|
||||
|
||||
const nonceResponse = await fetch(`${endpoint}/auth/nonce?address=${address}&type=solana`);
|
||||
const { nonce } = await nonceResponse.json();
|
||||
|
||||
const encodedMessage = new TextEncoder().encode(nonce);
|
||||
const signatureBytes = await provider.signMessage(encodedMessage, 'utf8');
|
||||
signature = bs58.encode(signatureBytes.signature);
|
||||
} else {
|
||||
throw new Error('Invalid type');
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${endpoint}/auth/verify`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ type, message, address, signature }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error((await response.json()).error);
|
||||
}
|
||||
|
||||
const { auth_token } = await response.json();
|
||||
|
||||
localStorage.setItem('auth_token', auth_token);
|
||||
localStorage.setItem('auth_type', type);
|
||||
|
||||
return { success: true, auth_token };
|
||||
} catch (error) {
|
||||
console.error('Authentication error:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
export async function signOff() {
|
||||
const auth_token = localStorage.getItem('auth_token');
|
||||
const response = await fetch(`${endpoint}/auth/signoff`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${auth_token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error((await response.json()).error);
|
||||
} else {
|
||||
localStorage.removeItem('auth_token');
|
||||
return true;
|
||||
}
|
||||
}
|
25
webpack.config.js
Normal file
25
webpack.config.js
Normal file
@ -0,0 +1,25 @@
|
||||
const path = require("path");
|
||||
const webpack = require("webpack");
|
||||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
|
||||
module.exports = {
|
||||
entry: "./index.js",
|
||||
output: {
|
||||
filename: "bundle.js",
|
||||
path: path.resolve(__dirname, "dist")
|
||||
},
|
||||
plugins: [
|
||||
new TerserPlugin({
|
||||
terserOptions: {
|
||||
keep_fnames: ['signIn', 'fetchProtected'],
|
||||
mangle: {
|
||||
reserved: [
|
||||
"signIn",
|
||||
"fetchProtected"
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
],
|
||||
mode: "development"
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user