Skip to content

Commit

Permalink
Iterate
Browse files Browse the repository at this point in the history
  • Loading branch information
serefyarar committed Oct 3, 2024
1 parent b7c31ac commit e24fd17
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 1,207 deletions.
2 changes: 0 additions & 2 deletions web-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"@lit-protocol/uint8arrays": "4.1.1",
"@magicbell/user-client": "^0.2.0",
"@magicbell/webpush": "^2.0.2",
"@metamask/sdk-react": "^0.28.0",
"@nanostores/react": "ai/react",
"@radix-ui/react-alert-dialog": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.4",
Expand Down Expand Up @@ -63,7 +62,6 @@
"lodash.debounce": "^4.0.8",
"lottie-react": "^2.3.1",
"lottie-react-web": "^2.2.2",
"magicbell": "^3.3.0",
"moment": "^2.29.3",
"multiformats": "^12.1.1",
"nanoid": "^5.0.7",
Expand Down
2 changes: 0 additions & 2 deletions web-app/src/app/new/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ import { useAuth } from "@/context/AuthContext";
import { DIDSession } from "did-session";
import { createIndex } from "@/store/api";
import { useAppDispatch } from "@/store/store";
import { useSDK } from "@metamask/sdk-react";

const Home: NextPage = () => {
const { transactionApprovalWaiting, handleTransactionCancel } = useApp();

const { provider: ethProvider, sdk } = useSDK();
const { setSession } = useAuth();

const { api, ready: apiReady } = useApi();
Expand Down
10 changes: 10 additions & 0 deletions web-app/src/components/layout/base/Navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ const Navbar = ({
const router = useRouter();
const { leftSidebarOpen, setLeftTabKey, setLeftSidebarOpen } = useApp();

/*
const [showTestnetWarning, setShowTestnetWarning] = useState(false);
useEffect(() => {
const handleChainChanged = (newChainId: string) => setShowTestnetWarning(newChainId !== appConfig.testNetwork.chainId);
handleChainChanged(window.ethereum?.chainId);
window.ethereum?.on("chainChanged", handleChainChanged);
return () => window.ethereum?.removeListener("chainChanged", handleChainChanged);
}, []);
*/

useEffect(() => {
if (sticky) {
if (typeof yOffSet === "number") {
Expand Down
18 changes: 0 additions & 18 deletions web-app/src/components/layout/site/AppHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,24 +170,6 @@ const AppHeader = () => {
</Text>
</div>
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => {
router.push("/notifications");
}}
>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "start",
}}
>
<IconHistory width={16} height="100%" />
<Text className="ml-3" element="span" size="md">
Notifications
</Text>
</div>
</DropdownMenuItem>
<DropdownMenuItem divider />
<DropdownMenuItem onClick={handleDisconnect}>
<div
Expand Down
13 changes: 0 additions & 13 deletions web-app/src/components/layout/site/AppLayout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,13 @@ import { ReactNode } from "react";
import { Toaster } from "react-hot-toast";
import { Provider } from "react-redux";
import store from "@/store/store";
import { MetaMaskProvider } from "@metamask/sdk-react";

interface AppLayoutProps {
children: ReactNode;
}

export const AppLayout = ({ children }: AppLayoutProps) => (
<Provider store={store}>
<MetaMaskProvider
debug={false}
sdkOptions={{
dappMetadata: {
name: "Index Network",
url: typeof window !== "undefined" ? window.location.href : "https://index.network",
},
infuraAPIKey: process.env.INFURA_API_KEY,
}}
>

<AuthProvider>
<APIProvider>
<PlausibleProvider domain="index.network">
Expand All @@ -37,6 +25,5 @@ export const AppLayout = ({ children }: AppLayoutProps) => (
</PlausibleProvider>
</APIProvider>
</AuthProvider>
</MetaMaskProvider>
</Provider>
);
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import Image from "next/image";
import Link from "next/link";
import React, { useCallback, useState } from "react";
import toast from "react-hot-toast";
import { useSDK } from "@metamask/sdk-react";
import { CodeSnippetReact, CodeSnippetsWithTabs } from "./CodeSnippets";
import SettingsModal, { SettingsModalStep } from "./SettingsModal";

Expand All @@ -18,7 +17,6 @@ const IndexSettingsTabSection: React.FC<IndexSettingsTabSectionProps> = () => {
const [secretKey, setSecretKey] = useState<string | undefined>();
const { isOwner } = useRole();
const [showModal, setShowModal] = useState(false);
const { provider: ethProvider, sdk } = useSDK();

const [step, setStep] = useState<SettingsModalStep>("waiting");

Expand All @@ -31,11 +29,7 @@ const IndexSettingsTabSection: React.FC<IndexSettingsTabSectionProps> = () => {
const handleCreate = useCallback(async () => {
setShowModal(true);
try {
if (!ethProvider || !sdk) {
throw new Error(`No metamask`);
}

const sessionResponse = await didService.getNewDIDSession(ethProvider, sdk);
const sessionResponse = await didService.getNewDIDSession();
setSecretKey(sessionResponse);
setStep("done");
} catch (e) {
Expand Down
157 changes: 64 additions & 93 deletions web-app/src/context/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ import { randomBytes, randomString } from "@stablelib/random";
import { DIDSession, createDIDCacao, createDIDKey } from "did-session";
import React, { useCallback, useEffect, useState } from "react";
import toast from "react-hot-toast";
import { useSDK } from "@metamask/sdk-react";

declare global {
interface Window {
ethereum: any;
}
}

export enum AuthStatus {
CONNECTED = "CONNECTED",
Expand Down Expand Up @@ -49,20 +54,6 @@ export const AuthContext =
export const AuthProvider = ({ children }: any) => {
const SESSION_KEY = "did";

const { provider: ethProvider, sdk } = useSDK();
const [isSDKConnected, setIsSDKConnected] = useState(false);

useEffect(() => {
const checkSDKConnection = async () => {
if (sdk && typeof sdk.isInitialized === 'function') {
const connected = sdk.isInitialized();
setIsSDKConnected(connected);
}
};

checkSDKConnection();
}, [sdk]);

const [session, setSession] = useState<DIDSession | undefined>();
const [status, setStatus] = useState<AuthStatus>(AuthStatus.IDLE);

Expand Down Expand Up @@ -101,73 +92,59 @@ export const AuthProvider = ({ children }: any) => {
return !existingSession.isExpired;
}, [session]);

const startSession = useCallback(async (): Promise<boolean> => {
if (!ethProvider || !sdk) {
console.warn("Ethereum provider or SDK not available");
return false;
}

try {
if (!isSDKConnected) {
const accounts = await sdk.connect();
if (!accounts || accounts.length === 0) {
throw new Error("Failed to connect accounts");
}
}

const accounts = await ethProvider.request({ method: 'eth_accounts' });
if (!accounts || accounts.length === 0) {
throw new Error("No accounts available");
}

const accountId = await getAccountId(ethProvider, accounts?.[0]);
const normAccount = normalizeAccountId(accountId);
const keySeed = randomBytes(32);
const didKey = await createDIDKey(keySeed);
console.log(didKey)
const now = new Date();
const twentyFiveDaysLater = new Date(
now.getTime() + 365 * 24 * 60 * 60 * 1000,
);

const siweMessage = new SiweMessage({
domain: window.location.host,
address: getAddress(normAccount.address),
statement: "Give this application access to some of your data on Ceramic",
uri: didKey.id,
version: "1",
chainId: "1",
nonce: randomString(10),
issuedAt: now.toISOString(),
expirationTime: twentyFiveDaysLater.toISOString(),
resources: ["ceramic://*"],
});

const signature = await ethProvider.request({
method: "personal_sign",
params: [siweMessage.signMessage(), getAddress(accountId.address)],
});
if (signature === null) {
throw new Error("Failed to sign message");
}

siweMessage.signature = signature as string
const cacao = Cacao.fromSiweMessage(siweMessage);
const did = await createDIDCacao(didKey, cacao);
const newSession = new DIDSession({ cacao, keySeed, did });

localStorage.setItem(SESSION_KEY, newSession.serialize());
setSession(newSession);
return true
} catch (error) {
console.error("Error starting session:", error);
return false;
}
}, [ethProvider, sdk, isSDKConnected]);
const startSession = useCallback(async (): Promise<void> => {
const ethProvider = window.ethereum;

// if (ethProvider.chainId !== appConfig.testNetwork.chainId) {
/*const switchRes = await switchTestNetwork();
if (!switchRes) {
throw new Error("Network error.");
}*/
// }

// request ethereum accounts.
const addresses = await ethProvider.enable({
method: "eth_requestAccounts",
});

const accountId = await getAccountId(ethProvider, addresses[0]);
const normAccount = normalizeAccountId(accountId);
const keySeed = randomBytes(32);
const didKey = await createDIDKey(keySeed);

const now = new Date();
const twentyFiveDaysLater = new Date(
now.getTime() + 365 * 24 * 60 * 60 * 1000,
);

const siweMessage = new SiweMessage({
domain: window.location.host,
address: getAddress(normAccount.address),
statement: "Give this application access to some of your data on Ceramic",
uri: didKey.id,
version: "1",
chainId: "1",
nonce: randomString(10),
issuedAt: now.toISOString(),
expirationTime: twentyFiveDaysLater.toISOString(),
resources: ["ceramic://*"],
});

siweMessage.signature = await ethProvider.request({
method: "personal_sign",
params: [siweMessage.signMessage(), getAddress(accountId.address)],
});

const cacao = Cacao.fromSiweMessage(siweMessage);
const did = await createDIDCacao(didKey, cacao);
const newSession = new DIDSession({ cacao, keySeed, did });

localStorage.setItem(SESSION_KEY, newSession.serialize());
setSession(newSession);
}, []);

const authenticate = useCallback(async () => {

if (!ethProvider) {
if (!window.ethereum) {
console.warn(
"Skipping wallet connection: No injected Ethereum provider found.",
);
Expand All @@ -185,26 +162,20 @@ export const AuthProvider = ({ children }: any) => {

if (!sessionIsValid) {
console.log("No valid session found, starting new session...");
const sessionResponse = await startSession();
if (sessionResponse) {
console.log("Session is valid, connecting...");

setStatus(AuthStatus.CONNECTED);
toast.success("Successfully connected to your wallet.");
trackEvent(WALLET_CONNECTED);
}else {
console.error("Error during authentication process");
setStatus(AuthStatus.FAILED);
}
await startSession();
}

console.log("Session is valid, connecting...");

setStatus(AuthStatus.CONNECTED);
toast.success("Successfully connected to your wallet.");
trackEvent(WALLET_CONNECTED);
} catch (err) {
console.error("Error during authentication process:", err);
setStatus(AuthStatus.FAILED);
toast.error("Failed to connect to your wallet. Please try again.");
}
}, [ethProvider, status, checkSession, startSession]);
}, [status, checkSession, startSession]);

return (
<AuthContext.Provider
Expand All @@ -230,4 +201,4 @@ export const useAuth = () => {
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
};
};
11 changes: 4 additions & 7 deletions web-app/src/services/did-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,14 @@ import { getAddress } from "@ethersproject/address";
import { HDNodeWallet, Wallet } from "ethers";

class DIDService {
async getNewDIDSession(ethProvider: any, sdk: any) {
// const { provider: ethProvider, sdk } = useSDK();
async getNewDIDSession() {
const ethProvider = window.ethereum;

// request ethereum accounts.
const addresses = await ethProvider?.request({
const addresses = await ethProvider.enable({
method: "eth_requestAccounts",
});

const accounts = await sdk?.connect();

const accountId = await getAccountId(ethProvider, accounts?.[0]);
const accountId = await getAccountId(ethProvider, addresses[0]);
const normAccount = normalizeAccountId(accountId);
const keySeed = randomBytes(32);
const didKey = await createDIDKey(keySeed);
Expand Down
11 changes: 11 additions & 0 deletions web-app/src/utils/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ export const setDates = <
return obj;
};

export const switchNetwork = async (chainId: string) => {
try {
await window.ethereum.request({
method: "wallet_switchEthereumChain",
params: [{ chainId }],
});
return true;
} catch (e: any) {
if (e.code === 4001) return false; // Reject to switch
}
};
export const getCurrentDateTime = () => moment.utc().toISOString();

const isValidUrl = (url: string) => {
Expand Down
Loading

0 comments on commit e24fd17

Please sign in to comment.