Re-adding signing capabilities and adding better UI

This commit is contained in:
Samuel Andert
2023-09-02 13:26:05 +02:00
parent 9b9ac7d89e
commit 61ba4d0e4f
11 changed files with 375 additions and 57 deletions

View File

@ -14,7 +14,7 @@
}
}
</script>
<body data-sveltekit-preload-data="hover">
<body data-theme="wintry" data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

54
src/lib/Signer.svelte Normal file
View File

@ -0,0 +1,54 @@
<script lang="ts">
import { signMessageWithPKP } from "$lib/services/signMessage";
import { walletState, messageToSign, messageSignature } from "$lib/stores.js";
let currentPKP;
let sessionSigs;
let message;
let signature;
walletState.subscribe((value) => {
currentPKP = value.pkps[0];
sessionSigs = value.sessionSigs;
});
messageToSign.subscribe((value) => {
message = value;
});
messageSignature.subscribe((value) => {
signature = value;
});
async function signMessage() {
const result = await signMessageWithPKP(sessionSigs, currentPKP, message);
if (result.error) {
console.error(result.error);
} else {
messageSignature.set(result.messageSignature);
}
}
function declineSign() {
messageSignature.set(null);
}
</script>
<div class="flex flex-col items-center justify-center h-full space-y-4">
<p class="text-lg break-words">{JSON.stringify(message)}</p>
{#if signature}
<p class="text-sm font-bold break-words">
Signature: {JSON.stringify(signature)}
</p>
{/if}
<div
class="absolute bottom-0 flex items-center justify-center w-full pb-4 space-x-4"
>
<button on:click={declineSign} class="btn variant-filled-error"
>Decline</button
>
<button on:click={signMessage} class="btn variant-filled-success"
>Sign</button
>
</div>
</div>

120
src/lib/SignerOLD.svelte Normal file
View File

@ -0,0 +1,120 @@
<!-- SignVerifyMessage.svelte -->
<script lang="ts">
import { ethers } from "ethers";
import { onMount } from "svelte";
import { signRequest, signedMessages } from "./stores.js";
let messageToSign = {};
let currentPKP;
let sessionSigs;
let status = "";
let litNodeClient;
let messageSignature;
onMount(async () => {
litNodeClient = new LitNodeClient({ litNetwork: "serrano" });
await litNodeClient.connect();
const sessionSigsLocalStorage = localStorage.getItem("google-session");
const currentPKPLocalStorage = localStorage.getItem("current-pkp");
if (sessionSigsLocalStorage && currentPKPLocalStorage) {
sessionSigs = JSON.parse(sessionSigsLocalStorage);
currentPKP = JSON.parse(currentPKPLocalStorage);
}
});
async function signMessageWithPKP() {
const userConfirmed = window.confirm(
"Do you want to sign the following message?\n\n" +
JSON.stringify(messageToSign, null, 2)
);
if (!userConfirmed) {
status = "User did not allow to sign the message.";
dispatch("status", status);
return;
}
try {
// Create a specific JSON object
const jsonString = JSON.stringify(messageToSign);
// Convert the JSON string to an array of character codes
const toSign = ethers.getBytes(ethers.hashMessage(jsonString));
const litActionCode = `
const go = async () => {
const sigShare = await LitActions.signEcdsa({ toSign, publicKey, sigName });
};
go();
`;
// Sign message
const results = await litNodeClient.executeJs({
code: litActionCode,
sessionSigs: sessionSigs,
jsParams: {
toSign: toSign,
publicKey: currentPKP.publicKey,
sigName: "sig1",
},
});
// Get signature
const result = results.signatures["sig1"];
messageSignature = ethers.Signature.from({
r: "0x" + result.r,
s: "0x" + result.s,
v: result.recid,
});
signedMessages.update((messages) => [
...messages,
{ json: messageToSign, signature: messageSignature },
]);
// verify();
} catch (err) {
console.error(err);
}
}
async function verify() {
const response = await fetch("/api/verify", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
messageToSign,
messageSignature,
currentPKP,
}),
});
if (!response.ok) {
alert("verify failed");
} else {
let json = await response.json();
alert(json.verified ? "Signature valid" : "! Signature NOT valid !");
}
}
signRequest.subscribe(({ json }) => {
if (messageToSign && Object.keys(json).length > 0) {
signRequest.set({ json: {} });
messageToSign = json;
signMessageWithPKP(json);
}
});
</script>
{#if status}
<div class="mt-4 text-center">
<p>Status: {status}</p>
</div>
{/if}
{#if messageSignature}
<div class="mt-4 text-center">
<p>Signature</p>
<pre>{JSON.stringify(messageSignature)}</pre>
</div>
<button on:click={verify}>Verify</button><br />
{/if}

View File

@ -3,13 +3,20 @@
import walletMachine from "./machines/walletMachine";
import { onMount } from "svelte";
import Icon from "@iconify/svelte";
import { walletState } from "./stores";
import { messageToSign } from "./stores";
import {
signInWithGoogle,
startSignIn as startSignInService,
} from "./services/signInWithGoogle";
import Signer from "./Signer.svelte";
import { getDrawerStore } from "@skeletonlabs/skeleton";
const { state, send } = useMachine(walletMachine);
const drawerStore = getDrawerStore();
$: walletState.set($state.context);
$: {
if ($state.context.pkps && $state.context.sessionSigs) {
@ -33,9 +40,16 @@
startSignInService.set(true);
await signInWithGoogle();
}
function clearSession() {
send("LOGOUT");
}
function signRequest() {
const settings = { position: "bottom", id: "signMessage" };
drawerStore.open(settings);
messageToSign.set({ hello: "test" });
}
</script>
{#if $state.matches("sessionAvailable") || $state.matches("creatingSession") || $state.matches("signIn")}
@ -43,7 +57,7 @@
<div class="w-1/3">
<button
on:click={startSignIn}
class="w-full py-2 text-white bg-blue-500 rounded hover:bg-blue-700 flex items-center justify-center"
class="flex items-center justify-center w-full py-2 text-white bg-blue-500 rounded hover:bg-blue-700"
>
<span class="mr-2"><Icon icon="flat-color-icons:google" /></span>
<span>Sign in with Google</span>
@ -51,9 +65,9 @@
</div>
{:else if $state.context.pkps}
<div
class="fixed bottom-0 left-0 right-0 p-3 bg-white bg-opacity-75 rounded-t-lg shadow-md flex flex-col items-center space-y-4"
class="fixed bottom-0 left-0 right-0 flex flex-col items-center p-3 space-y-4 bg-white bg-opacity-75 rounded-t-lg shadow-md"
>
<div class="w-full flex items-center justify-between space-x-4">
<div class="flex items-center justify-between w-full space-x-4">
<div class="flex items-center space-x-2">
<div>
<p class="text-sm">
@ -66,23 +80,23 @@
</p>
</div>
</div>
<button
on:click={clearSession}
class="py-1 px-2 text-white bg-red-500 rounded hover:bg-red-700"
<button on:click={signRequest} type="button" class="btn variant-filled"
>SignRequest</button
>
<button type="button" class="btn variant-filled" on:click={clearSession}
>Logout</button
>
Logout
</button>
</div>
</div>
{:else if $state.matches("sessionExpired")}
<div class="bg-white p-10">
<div class="p-10 bg-white">
<p>Error creating session. Please try again.</p>
<pre>{JSON.stringify($state.context.error, null, 2)}</pre>
</div>
{/if}
{:else}
<div class="bg-white p-10 rounded-full">
<div class="bg-white rounded-full p-5 animate-spin">
<div class="p-10 bg-white rounded-full">
<div class="p-5 bg-white rounded-full animate-spin">
<Icon icon="la:spinner" width="100" height="100" />
</div>
</div>

View File

@ -0,0 +1,41 @@
// $lib/services/signMessage.ts
import { ethers } from "ethers";
export async function signMessageWithPKP(sessionSigs, currentPKP, messageToSign) {
try {
const jsonString = JSON.stringify(messageToSign);
const toSign = ethers.getBytes(ethers.hashMessage(jsonString));
const litActionCode = `
const go = async () => {
const sigShare = await LitActions.signEcdsa({ toSign, publicKey, sigName });
};
go();
`;
const litNodeClient = new LitNodeClient({ litNetwork: "serrano" });
await litNodeClient.connect();
const results = await litNodeClient.executeJs({
code: litActionCode,
sessionSigs: sessionSigs,
jsParams: {
toSign: toSign,
publicKey: currentPKP.publicKey,
sigName: "sig1",
},
});
const result = results.signatures["sig1"];
const messageSignature = ethers.Signature.from({
r: "0x" + result.r,
s: "0x" + result.s,
v: result.recid,
});
return { messageSignature };
} catch (err) {
console.error(err);
return { error: err };
}
}

View File

@ -1,11 +1,13 @@
import { writable } from 'svelte/store';
export const signRequest = writable({json: {}});
export const signedMessages = writable([])
export const redirectStore = writable(false);
export const walletState = writable(null);
export const messageToSign = writable(null);
export const messageSignature = writable(null);
export const googleSession = writable({
activeSession: false
});

View File

@ -8,6 +8,13 @@
import { initChainProvider } from "$lib/setupChainProvider";
import { googleSession } from "$lib/stores.js";
import Wallet from "$lib/Wallet.svelte";
import { Drawer, initializeStores } from "@skeletonlabs/skeleton";
import { getDrawerStore } from "@skeletonlabs/skeleton";
import Signer from "$lib/Signer.svelte";
initializeStores();
const drawerStore = getDrawerStore();
let activeSession = false;
@ -28,8 +35,16 @@
}
</script>
<Drawer>
{#if $drawerStore.id === "signMessage"}
<Signer messageToSign={{ hello: "me" }} />
{:else}
<!-- (fallback contents) -->
{/if}</Drawer
>
<div
class="flex items-center justify-center h-screen bg-cover bg-center"
class="flex items-center justify-center h-screen bg-center bg-cover"
style="background-image: url('lake.jpeg');"
>
<QueryClientProvider client={data.queryClient}>