Implement persisting session (#5)
* Add layout to pages * Persist session * Style sign with ethereum page * Refactor modal * Remove unused styles * Implement disconnect session functionality * Add info about wallet in navbar * Remove unused imports * Use canonical JSON * Add line * Remove buffer from sign with ethereum page * Display signed message in dialog * Show modal on signature * Format cosmos signature * Add code block style for json messages * Display signature in first modal * Add urbit logo for connect wallet page * Display message for sign with ethereum * Handle review changes * Keep icon and text on same line --------- Co-authored-by: neeraj <neeraj.rtly@gmail.com> Co-authored-by: Adw8 <adwait@deepstacksoft.com>
This commit is contained in:
parent
5e98e2e25a
commit
6bdaf60ff4
@ -20,6 +20,7 @@
|
||||
"@walletconnect/types": "^2.11.3",
|
||||
"assert": "^2.1.0",
|
||||
"buffer": "^6.0.3",
|
||||
"canonical-json": "^0.0.4",
|
||||
"notistack": "^3.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
@ -1,18 +1,21 @@
|
||||
import React from "react";
|
||||
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
||||
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
||||
|
||||
import ConnectWallet from "./pages/ConnectWallet";
|
||||
import SignWithEthereum from "./pages/SignWithEthereum";
|
||||
import SignWithCosmos from "./pages/SignWithCosmos";
|
||||
import PageNotFound from "./pages/PageNotFound";
|
||||
import SignPageLayout from "./layout/SignPageLayout";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/" element={<ConnectWallet />} />
|
||||
<Route path="/sign-with-ethereum" element={<SignWithEthereum />} />
|
||||
<Route path="/sign-with-cosmos/:ethAddress/:cosmosAddress/:ethSignature" element={<SignWithCosmos />} />
|
||||
<Route element={<SignPageLayout />} >
|
||||
<Route path="/sign-with-ethereum" element={<SignWithEthereum />} />
|
||||
<Route path="/sign-with-cosmos/:ethAddress/:cosmosAddress/:ethSignature" element={<SignWithCosmos />} />
|
||||
</Route>
|
||||
<Route path="*" element={<PageNotFound />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
|
@ -5,11 +5,13 @@ import React, {
|
||||
ReactNode,
|
||||
useState,
|
||||
useEffect,
|
||||
useCallback,
|
||||
} from "react";
|
||||
|
||||
import SignClient from "@walletconnect/sign-client";
|
||||
import { WalletConnectModal } from "@walletconnect/modal";
|
||||
import { SessionTypes } from "@walletconnect/types";
|
||||
import { getSdkError } from "@walletconnect/utils";
|
||||
|
||||
const PROJECT_ID = process.env.REACT_APP_WALLET_CONNECT_ID;
|
||||
assert(PROJECT_ID, "Wallet connect project id not provided");
|
||||
@ -18,12 +20,16 @@ interface ContextValue {
|
||||
connect: () => Promise<void>;
|
||||
session: SessionTypes.Struct | null;
|
||||
signClient: SignClient | undefined;
|
||||
checkPersistedState: (client: SignClient)=> Promise<void>
|
||||
disconnect: () => Promise<void>;
|
||||
}
|
||||
|
||||
const walletConnectContext = createContext<ContextValue>({
|
||||
connect: () => Promise.resolve(),
|
||||
session: null,
|
||||
signClient: undefined,
|
||||
checkPersistedState: ()=> Promise.resolve(),
|
||||
disconnect: () => Promise.resolve(),
|
||||
});
|
||||
|
||||
const web3Modal = new WalletConnectModal({
|
||||
@ -40,7 +46,28 @@ export const WalletConnectProvider = ({
|
||||
const [signClient, setSignClient] = useState<SignClient>();
|
||||
const [session, setSession] = useState<SessionTypes.Struct | null>(null);
|
||||
|
||||
const createClient = async () => {
|
||||
const disconnect = useCallback(async () => {
|
||||
if (signClient && session) {
|
||||
await signClient.disconnect({
|
||||
topic: session.topic,
|
||||
reason: getSdkError("USER_DISCONNECTED"),
|
||||
});
|
||||
}
|
||||
|
||||
setSession(null)
|
||||
}, [signClient, session]);
|
||||
|
||||
const checkPersistedState = useCallback(async(client: SignClient)=>{
|
||||
if (client.session.length) {
|
||||
const lastKeyIndex = client.session.keys.length - 1;
|
||||
const session = client.session.get(
|
||||
client.session.keys[lastKeyIndex]
|
||||
);
|
||||
setSession(session)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const createClient = useCallback(async () => {
|
||||
const signClient = await SignClient.init({
|
||||
projectId: PROJECT_ID,
|
||||
metadata: {
|
||||
@ -52,7 +79,8 @@ export const WalletConnectProvider = ({
|
||||
});
|
||||
|
||||
setSignClient(signClient);
|
||||
};
|
||||
await checkPersistedState(signClient)
|
||||
}, [checkPersistedState])
|
||||
|
||||
const connect = async () => {
|
||||
if (!signClient) {
|
||||
@ -88,7 +116,7 @@ export const WalletConnectProvider = ({
|
||||
if (!signClient) {
|
||||
createClient();
|
||||
}
|
||||
}, [signClient]);
|
||||
}, [signClient, createClient]);
|
||||
|
||||
return (
|
||||
<walletConnectContext.Provider
|
||||
@ -96,6 +124,8 @@ export const WalletConnectProvider = ({
|
||||
connect,
|
||||
session,
|
||||
signClient,
|
||||
checkPersistedState,
|
||||
disconnect
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
@ -108,11 +138,15 @@ export const useWalletConnectContext = () => {
|
||||
connect,
|
||||
session,
|
||||
signClient,
|
||||
checkPersistedState,
|
||||
disconnect
|
||||
} = useContext(walletConnectContext);
|
||||
|
||||
return {
|
||||
connect,
|
||||
session,
|
||||
signClient,
|
||||
checkPersistedState,
|
||||
disconnect
|
||||
};
|
||||
};
|
||||
|
1
src/decs.d.ts
vendored
Normal file
1
src/decs.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
declare module 'canonical-json'
|
76
src/layout/SignPageLayout.tsx
Normal file
76
src/layout/SignPageLayout.tsx
Normal file
@ -0,0 +1,76 @@
|
||||
import React from "react";
|
||||
import { Outlet, useNavigate } from "react-router-dom";
|
||||
|
||||
import {
|
||||
Toolbar,
|
||||
IconButton,
|
||||
Avatar,
|
||||
Button,
|
||||
Typography,
|
||||
Container,
|
||||
} from "@mui/material";
|
||||
|
||||
import { useWalletConnectContext } from "../context/WalletConnectContext";
|
||||
|
||||
const SignPageLayout = () => {
|
||||
const { disconnect, session } = useWalletConnectContext();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const disconnectHandler = async () => {
|
||||
await disconnect();
|
||||
navigate("/");
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Toolbar variant="dense">
|
||||
<Avatar
|
||||
alt="Urbit logo"
|
||||
src="https://avatars.githubusercontent.com/u/5237680?s=200&v=4"
|
||||
/>
|
||||
<IconButton
|
||||
edge="start"
|
||||
color="inherit"
|
||||
aria-label="menu"
|
||||
sx={{ mr: 2 }}
|
||||
>
|
||||
Urbit
|
||||
</IconButton>
|
||||
|
||||
<Button
|
||||
variant="outlined"
|
||||
style={{
|
||||
marginLeft: "auto",
|
||||
}}
|
||||
onClick={disconnectHandler}
|
||||
>
|
||||
Disconnect
|
||||
</Button>
|
||||
</Toolbar>
|
||||
|
||||
<Container maxWidth="md">
|
||||
{session && (
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
<div style={{ display: "flex", flexDirection: "row", alignItems: 'flex-end' }}>
|
||||
<Typography variant="body2">
|
||||
Connected to: <b> {session.peer.metadata.name}</b>{" "}
|
||||
</Typography>
|
||||
<Avatar
|
||||
variant="square"
|
||||
alt="Peer logo"
|
||||
src={session.peer.metadata.icons[0]}
|
||||
sx={{ width: 20, height: 20, marginLeft: 1, paddingBottom: 0.5 }}
|
||||
/>
|
||||
</div>
|
||||
<Typography variant="body2">
|
||||
Session ID: <b>{session.topic} </b>
|
||||
</Typography>
|
||||
</div>
|
||||
)}
|
||||
<Outlet />
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SignPageLayout;
|
@ -1,22 +1,46 @@
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
import { Typography, Button, Box, Grid, Avatar } from '@mui/material';
|
||||
|
||||
import { useWalletConnectContext } from "../context/WalletConnectContext";
|
||||
|
||||
// TODO: Connect wallet should not be accessible if session already exists
|
||||
const ConnectWallet = () => {
|
||||
const { connect } = useWalletConnectContext();
|
||||
const { connect, session } = useWalletConnectContext();
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
if (session) {
|
||||
navigate("/sign-with-ethereum")
|
||||
}
|
||||
const handler = async () => {
|
||||
await connect();
|
||||
navigate("/sign-with-ethereum")
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Connect wallet </h1>
|
||||
<button onClick={handler}>Connect</button>
|
||||
</div>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={2}>
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
<Box display="flex" flexDirection="column" alignItems="center" height="50vh" justifyContent="center" padding={5}>
|
||||
<Box display="flex" alignItems="center">
|
||||
<Avatar alt="Urbit logo" src="https://avatars.githubusercontent.com/u/5237680?s=200&v=4" />
|
||||
<Typography variant="h4" component="h6">
|
||||
Urbit Onboarding
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography variant="h6" component="h6" style={{ marginTop: '30px' }}>
|
||||
Connect wallet
|
||||
</Typography>
|
||||
<Button variant="contained" onClick={handler} style={{ marginTop: '20px' }}>
|
||||
Connect
|
||||
</Button>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={2}>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,44 +1,59 @@
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { SnackbarProvider, enqueueSnackbar } from "notistack";
|
||||
import canonicalStringify from "canonical-json";
|
||||
|
||||
import { Modal, Button, Typography, Box } from "@mui/material";
|
||||
import Alert from "@mui/material/Alert";
|
||||
import CheckIcon from "@mui/icons-material/Check";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Box,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
|
||||
import { useWalletConnectContext } from "../context/WalletConnectContext";
|
||||
|
||||
const style = {
|
||||
position: "absolute" as const,
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
overflow: "scroll",
|
||||
bgcolor: "background.paper",
|
||||
border: "2px solid #000",
|
||||
boxShadow: 24,
|
||||
p: 4,
|
||||
};
|
||||
|
||||
const SignWithCosmos = () => {
|
||||
const { session, signClient } = useWalletConnectContext();
|
||||
|
||||
const { ethAddress, cosmosAddress, ethSignature } = useParams();
|
||||
|
||||
const [openModal, setOpenModal] = useState(false);
|
||||
const [result, setResult] = useState("");
|
||||
const [cosmosSignature, setCosmosSignature] = useState("");
|
||||
|
||||
const message = useMemo(() => {
|
||||
return JSON.stringify(
|
||||
const displayAttestation = useMemo(() => {
|
||||
return canonicalStringify(
|
||||
{
|
||||
ethAddress,
|
||||
ethSignature,
|
||||
text: "Attested by ethereum key",
|
||||
payload: {
|
||||
msg: "Onboarding my Azimuth ID onto UrbitChain",
|
||||
address: ethAddress,
|
||||
payload: {
|
||||
msg: "Onboarding my cosmos validator onto UrbitChain",
|
||||
address: cosmosAddress,
|
||||
},
|
||||
},
|
||||
signatures: [cosmosSignature, ethSignature],
|
||||
},
|
||||
null,
|
||||
2
|
||||
);
|
||||
}, [ethAddress, ethSignature]);
|
||||
}, [ethAddress, cosmosAddress, cosmosSignature, ethSignature]);
|
||||
|
||||
const message = useMemo(() => {
|
||||
return canonicalStringify(
|
||||
{
|
||||
msg: "Onboarding my Azimuth ID onto UrbitChain",
|
||||
address: ethAddress,
|
||||
payload: {
|
||||
msg: "Onboarding my cosmos validator onto UrbitChain",
|
||||
address: cosmosAddress,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
);
|
||||
}, [ethAddress, cosmosAddress]);
|
||||
|
||||
const signCosmos = async () => {
|
||||
try {
|
||||
@ -62,8 +77,8 @@ const SignWithCosmos = () => {
|
||||
params,
|
||||
},
|
||||
});
|
||||
setOpenModal(false);
|
||||
setResult(signedMessage.signature);
|
||||
setOpenModal(true);
|
||||
setCosmosSignature(signedMessage.signature);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("err in signing ", error);
|
||||
@ -73,57 +88,69 @@ const SignWithCosmos = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Sign using Cosmos key</h1>
|
||||
<p>Cosmos account: {cosmosAddress}</p>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setOpenModal(true);
|
||||
<Box
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
marginTop: "100px",
|
||||
gap: "10px",
|
||||
}}
|
||||
>
|
||||
<Typography variant="h5">Sign with cosmos key</Typography>
|
||||
<Typography variant="body1">Cosmos account: {cosmosAddress}</Typography>
|
||||
<Typography variant="body1">
|
||||
Message: <br />
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: "lightgray",
|
||||
padding: 3,
|
||||
wordWrap: "break-word",
|
||||
}}
|
||||
>
|
||||
Sign with cosmos
|
||||
</Button>
|
||||
<Modal
|
||||
<pre style={{ whiteSpace: "pre-wrap", margin: 0 }}>{message} </pre>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
signCosmos();
|
||||
}}
|
||||
>
|
||||
Sign with cosmos
|
||||
</Button>
|
||||
</Box>
|
||||
<Dialog
|
||||
open={openModal}
|
||||
onClose={() => setOpenModal(false)}
|
||||
aria-labelledby="modal-modal-title"
|
||||
aria-describedby="modal-modal-description"
|
||||
onClose={() => {
|
||||
setOpenModal(false);
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
maxWidth="md"
|
||||
>
|
||||
<Box sx={style}>
|
||||
<Typography id="modal-modal-title" variant="h6" component="h2">
|
||||
Sign with Cosmos
|
||||
</Typography>
|
||||
<Typography id="modal-modal-description">Message to sign:</Typography>
|
||||
<Typography id="modal-modal-description" sx={{ mt: 2 }}>
|
||||
{message}
|
||||
</Typography>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
<DialogContent>
|
||||
Attested message to be broadcasted on chain
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: "lightgray",
|
||||
padding: 3,
|
||||
wordWrap: "break-word",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
onClick={() => {
|
||||
signCosmos();
|
||||
}}
|
||||
>
|
||||
Sign
|
||||
</Button>
|
||||
<Button onClick={() => setOpenModal(false)}>X</Button>
|
||||
</div>
|
||||
</Box>
|
||||
</Modal>
|
||||
<pre style={{ whiteSpace: "pre-wrap", margin: 0 }}>
|
||||
{displayAttestation}{" "}
|
||||
</pre>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setOpenModal(false)}>Close</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
{result && (
|
||||
<Alert icon={<CheckIcon fontSize="inherit" />} severity="success">
|
||||
Signed message ({result}) will be broadcasted to the chain
|
||||
</Alert>
|
||||
)}
|
||||
<SnackbarProvider />
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,148 +1,185 @@
|
||||
import React, { useState, useMemo } from "react";
|
||||
import assert from "assert";
|
||||
import React, { useState, useMemo, useEffect, useCallback } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { SnackbarProvider, enqueueSnackbar } from "notistack";
|
||||
import canonicalStringify from "canonical-json";
|
||||
|
||||
import {
|
||||
Modal,
|
||||
Button,
|
||||
Typography,
|
||||
Box,
|
||||
Select,
|
||||
MenuItem,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Box,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { utf8ToHex } from "@walletconnect/encoding";
|
||||
|
||||
import { useWalletConnectContext } from "../context/WalletConnectContext";
|
||||
|
||||
const style = {
|
||||
position: "absolute" as const,
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
overflow: "scroll",
|
||||
bgcolor: "background.paper",
|
||||
border: "2px solid #000",
|
||||
boxShadow: 24,
|
||||
p: 4,
|
||||
};
|
||||
|
||||
const SignWithEthereum = () => {
|
||||
window.Buffer = Buffer;
|
||||
const { session, signClient, checkPersistedState } =
|
||||
useWalletConnectContext();
|
||||
|
||||
useEffect(() => {
|
||||
if (signClient && !session) {
|
||||
checkPersistedState(signClient);
|
||||
}
|
||||
}, [session, signClient, checkPersistedState]);
|
||||
|
||||
const { session, signClient } = useWalletConnectContext();
|
||||
const navigate = useNavigate();
|
||||
const [ethAddress, setEthAddress] = useState("");
|
||||
const [ethSignature, setEthSignature] = useState("");
|
||||
|
||||
const [cosmosAddress, setCosmosAddress] = useState("");
|
||||
|
||||
const [openModal, setOpenModal] = useState(false);
|
||||
|
||||
const message = useMemo(() => {
|
||||
return {
|
||||
cosmosAddress,
|
||||
text: "Onboarding azimuth ID onto urbit chain",
|
||||
msg: "Onboarding my cosmos validator onto UrbitChain",
|
||||
address: cosmosAddress,
|
||||
};
|
||||
}, [cosmosAddress]);
|
||||
|
||||
const signEth = async () => {
|
||||
try {
|
||||
const jsonMessage = JSON.stringify(message, null, 2);
|
||||
const hexMsg = utf8ToHex(jsonMessage, true);
|
||||
const ethSignature: string = await signClient!.request({
|
||||
topic: session!.topic,
|
||||
chainId: "eip155:1",
|
||||
request: {
|
||||
method: "personal_sign",
|
||||
params: [hexMsg, ethAddress],
|
||||
},
|
||||
});
|
||||
navigate(
|
||||
`/sign-with-cosmos/${ethAddress}/${cosmosAddress}/${ethSignature}`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log("err in signing ", error);
|
||||
setOpenModal(false);
|
||||
enqueueSnackbar("Error signing message", { variant: "error" })
|
||||
if (session && signClient) {
|
||||
try {
|
||||
const jsonMessage = canonicalStringify(message);
|
||||
const hexMsg = utf8ToHex(jsonMessage, true);
|
||||
const ethSignature: string = await signClient!.request({
|
||||
topic: session!.topic,
|
||||
chainId: "eip155:1",
|
||||
request: {
|
||||
method: "personal_sign",
|
||||
params: [hexMsg, ethAddress],
|
||||
},
|
||||
});
|
||||
setEthSignature(ethSignature);
|
||||
setOpenModal(true);
|
||||
} catch (error) {
|
||||
console.log("err in signing ", error);
|
||||
setOpenModal(false);
|
||||
enqueueSnackbar("Error signing message", { variant: "error" });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
assert(session, "Session not found");
|
||||
const submitHandler = useCallback(() => {
|
||||
navigate(
|
||||
`/sign-with-cosmos/${ethAddress}/${cosmosAddress}/${ethSignature}`
|
||||
);
|
||||
setOpenModal(false);
|
||||
}, [ethAddress, cosmosAddress, ethSignature, navigate]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Connected</h1>
|
||||
<p>Session id: {session.topic}</p>
|
||||
<p>Select Cosmos accounts: </p>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={cosmosAddress}
|
||||
label="Cosmos address"
|
||||
onChange={(e: any) => {
|
||||
setCosmosAddress(e.target.value);
|
||||
}}
|
||||
style={{ maxWidth: "500px", display: "block" }}
|
||||
>
|
||||
{session.namespaces.cosmos.accounts.map((address, index) => (
|
||||
<MenuItem value={address.split(":")[2]} key={index}>
|
||||
{address.split(":")[2]}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<p>Select Ethereum account: </p>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={ethAddress}
|
||||
label="Ethereum address"
|
||||
onChange={(e: any) => {
|
||||
setEthAddress(e.target.value);
|
||||
}}
|
||||
style={{ maxWidth: "500px", display: "block" }}
|
||||
>
|
||||
{session.namespaces.eip155.accounts.map((address, index) => (
|
||||
<MenuItem value={address.split(":")[2]} key={index}>
|
||||
{address.split(":")[2]}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{session ? (
|
||||
<Box
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
marginTop: "100px",
|
||||
gap: "10px",
|
||||
}}
|
||||
>
|
||||
<Typography variant="h5">Sign with ethereum key</Typography>
|
||||
<Typography variant="body1">Select Cosmos account:</Typography>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={cosmosAddress}
|
||||
label="Cosmos address"
|
||||
onChange={(e: any) => {
|
||||
setCosmosAddress(e.target.value);
|
||||
}}
|
||||
style={{ maxWidth: "600px", display: "block" }}
|
||||
>
|
||||
{session?.namespaces.cosmos.accounts.map((address, index) => (
|
||||
<MenuItem value={address.split(":")[2]} key={index}>
|
||||
{address.split(":")[2]}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<Typography variant="body1">Select Ethereum account: </Typography>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={ethAddress}
|
||||
label="Ethereum address"
|
||||
onChange={(e: any) => {
|
||||
setEthAddress(e.target.value);
|
||||
}}
|
||||
style={{ maxWidth: "600px", display: "block" }}
|
||||
>
|
||||
{session?.namespaces.eip155.accounts.map((address, index) => (
|
||||
<MenuItem value={address.split(":")[2]} key={index}>
|
||||
{address.split(":")[2]}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
<Button
|
||||
onClick={() => {
|
||||
setOpenModal(true);
|
||||
}}
|
||||
disabled={!Boolean(ethAddress)}
|
||||
>
|
||||
Sign using Ethereum key
|
||||
</Button>
|
||||
<Modal
|
||||
open={openModal}
|
||||
onClose={() => setOpenModal(false)}
|
||||
aria-labelledby="modal-modal-title"
|
||||
aria-describedby="modal-modal-description"
|
||||
>
|
||||
<Box sx={style}>
|
||||
<Typography id="modal-modal-title" variant="h6" component="h2">
|
||||
Sign using ethereum ({ethAddress})
|
||||
</Typography>
|
||||
<Typography id="modal-modal-description">Message to sign:</Typography>
|
||||
<Typography id="modal-modal-description" sx={{ mt: 2 }}>
|
||||
{JSON.stringify(message, null, 2)}
|
||||
</Typography>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
{ Boolean(ethAddress) && (<Box
|
||||
sx={{
|
||||
backgroundColor: "lightgray",
|
||||
padding: 3,
|
||||
wordWrap: "break-word",
|
||||
}}
|
||||
>
|
||||
<Button onClick={signEth}>Sign</Button>
|
||||
<Button onClick={() => setOpenModal(false)}>Close</Button>
|
||||
</div>
|
||||
<pre style={{ whiteSpace: "pre-wrap", margin: 0 }}>{JSON.stringify(message, null, 2)} </pre>
|
||||
</Box>)}
|
||||
<Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={signEth}
|
||||
disabled={!Boolean(ethAddress)}
|
||||
style={{ marginTop: "20px" }}
|
||||
>
|
||||
Sign using Ethereum key
|
||||
</Button>
|
||||
</Box>
|
||||
<Dialog
|
||||
open={openModal}
|
||||
onClose={() => {
|
||||
setOpenModal(false);
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
maxWidth="md"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
{"Signed message with ethereum key"}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography variant="body1" style={{ wordWrap: "break-word" }}>
|
||||
Signature: {ethSignature}
|
||||
</Typography>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: "lightgray",
|
||||
padding: 3,
|
||||
wordWrap: "break-word",
|
||||
}}
|
||||
>
|
||||
<pre style={{ whiteSpace: "pre-wrap", margin: 0 }}>
|
||||
{canonicalStringify(message, null, 2)}{" "}
|
||||
</pre>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={submitHandler} autoFocus>
|
||||
Sign with cosmos
|
||||
</Button>
|
||||
<Button onClick={() => setOpenModal(false)}>Close</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<SnackbarProvider />
|
||||
</Box>
|
||||
</Modal>
|
||||
<SnackbarProvider />
|
||||
) : (
|
||||
<>Loading...</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -4100,6 +4100,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001591:
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz#571cf4f3f1506df9bf41fcbb6d10d5d017817bce"
|
||||
integrity sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==
|
||||
|
||||
canonical-json@^0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/canonical-json/-/canonical-json-0.0.4.tgz#6579c072c3db5c477ec41dc978fbf2b8f41074a3"
|
||||
integrity sha512-2sW7x0m/P7dqEnO0O87U7RTVQAaa7MELcd+Jd9FA6CYgYtwJ1TlDWIYMD8nuMkH1KoThsJogqgLyklrt9d/Azw==
|
||||
|
||||
case-sensitive-paths-webpack-plugin@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"
|
||||
|
Loading…
Reference in New Issue
Block a user