Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RPC endpoint and optimized onboarding #50

Merged
merged 1 commit into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions front/src/app/api/users/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
import { PUBLIC_CLIENT } from "@/constants/client";
import { FACTORY_ABI } from "@/constants/factory";
import { Hex, createPublicClient, stringify, toHex, fallback, http } from "viem";
import { sepolia } from "viem/chains";
import { Hex, stringify, toHex } from "viem";

export async function GET(_req: Request, { params }: { params: { id: Hex } }) {
const { id } = params;
if (!id) {
return Response.json(JSON.parse(stringify({ error: "id is required" })));
}

const CLIENT = createPublicClient({
chain: sepolia,
transport: fallback([
http("https://rpc.notadegen.com/eth/sepolia"),
http("https://gateway.tenderly.co/public/sepolia "),
]),
});

const user = await CLIENT.readContract({
const user = await PUBLIC_CLIENT.readContract({
address: process.env.NEXT_PUBLIC_FACTORY_CONTRACT_ADDRESS as Hex,
abi: FACTORY_ABI,
functionName: "getUser",
args: [BigInt(id)],
});

const balance = await CLIENT.getBalance({ address: user.account });
const balance = await PUBLIC_CLIENT.getBalance({ address: user.account });

console.log("balance", balance);

Expand Down
44 changes: 26 additions & 18 deletions front/src/app/api/users/save/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CHAIN } from "@/constants";
import { CHAIN, PUBLIC_CLIENT, transport } from "@/constants";
import { FACTORY_ABI } from "@/constants/factory";
import { Hex, createPublicClient, createWalletClient, http, toHex, zeroAddress } from "viem";
import { Hex, createWalletClient, toHex, zeroAddress } from "viem";
import { privateKeyToAccount } from "viem/accounts";

export async function POST(req: Request) {
Expand All @@ -10,15 +10,10 @@ export async function POST(req: Request) {
const walletClient = createWalletClient({
account,
chain: CHAIN,
transport: http(),
transport,
});

const publicClient = createPublicClient({
chain: CHAIN,
transport: http(),
});

const user = await publicClient.readContract({
const user = await PUBLIC_CLIENT.readContract({
address: process.env.NEXT_PUBLIC_FACTORY_CONTRACT_ADDRESS as Hex,
abi: FACTORY_ABI,
functionName: "getUser",
Expand All @@ -29,28 +24,41 @@ export async function POST(req: Request) {
return Response.json(undefined);
}

const hash = await walletClient.writeContract({
await walletClient.writeContract({
address: process.env.NEXT_PUBLIC_FACTORY_CONTRACT_ADDRESS as Hex,
abi: FACTORY_ABI,
functionName: "saveUser",
args: [BigInt(id), pubKey],
});

await publicClient.waitForTransactionReceipt({ hash });

const createdUser = await publicClient.readContract({
const smartWalletAddress = await PUBLIC_CLIENT.readContract({
address: process.env.NEXT_PUBLIC_FACTORY_CONTRACT_ADDRESS as Hex,
abi: FACTORY_ABI,
functionName: "getUser",
args: [BigInt(id)],
functionName: "getAddress",
args: [pubKey],
});

// await PUBLIC_CLIENT.waitForTransactionReceipt({ hash });

// const createdUser = await PUBLIC_CLIENT.readContract({
// address: process.env.NEXT_PUBLIC_FACTORY_CONTRACT_ADDRESS as Hex,
// abi: FACTORY_ABI,
// functionName: "getUser",
// args: [BigInt(id)],
// });

// send 1 wei to the user
// so that anyone can send a transaction to the user's smart wallet
walletClient.sendTransaction({
to: createdUser.account,
await walletClient.sendTransaction({
to: smartWalletAddress,
value: BigInt(1),
});

return Response.json({ ...createdUser, id: toHex(createdUser.id) });
const createdUser = {
id,
account: smartWalletAddress,
pubKey,
};

return Response.json(createdUser);
}
15 changes: 6 additions & 9 deletions front/src/constants/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,16 @@ import { sepolia, mainnet } from "viem/chains";

export const CHAIN = {
...sepolia,
// rpcUrls: {
// ...sepolia.rpcUrls,
// default: { http: ["https://rpc.ankr.com/eth_sepolia"] },
// public: { http: ["https://rpc.ankr.com/eth_sepolia"] },
// },
};

export const transport = fallback([
http("https://rpc.notadegen.com/eth/sepolia"),
http("https://gateway.tenderly.co/public/sepolia "),
]);

export const PUBLIC_CLIENT = createPublicClient({
chain: sepolia,
transport: fallback([
http("https://ethereum-sepolia.publicnode.com"),
http("https://gateway.tenderly.co/public/sepolia "),
]),
transport,
});

export const MAINNET_PUBLIC_CLIENT = createPublicClient({
Expand Down
19 changes: 19 additions & 0 deletions front/src/constants/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,23 @@ export const FACTORY_ABI = [
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes32[2]",
name: "publicKey",
type: "bytes32[2]",
},
],
name: "getAddress",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
] as const;
7 changes: 6 additions & 1 deletion front/src/providers/BalanceProvider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { getUser } from "@/libs/factory/getUser";
import { useMe } from "@/providers/MeProvider";
import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
import { Hex, formatEther } from "viem";
import { Hex, formatEther, zeroAddress } from "viem";

function useBalanceHook() {
// balance in usd
Expand All @@ -14,6 +14,11 @@ function useBalanceHook() {

const getBalance = useCallback(async (keyId: Hex) => {
const user = await getUser(keyId);
if (user?.account === zeroAddress || user?.account === undefined) {
setBalance("0.00");
return;
}

console.log(user.balance);
const priceData = await fetch("/api/price?ids=ethereum&currencies=usd");
const price: number = Math.trunc((await priceData.json()).ethereum.usd * 100);
Expand Down
23 changes: 15 additions & 8 deletions front/src/providers/MeProvider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { createContext, useContext, useEffect, useState } from "react";
import { Address, Hex } from "viem";
import { Address, Hex, zeroAddress } from "viem";
import { WebAuthn } from "@/libs/web-authn/service/web-authn";
import { saveUser } from "@/libs/factory";
import { getUser } from "@/libs/factory/getUser";
Expand All @@ -23,7 +23,7 @@ function useMeHook() {
const [isMounted, setIsMounted] = useState(false);

function disconnect() {
localStorage.removeItem("hocuspocus.me");
localStorage.removeItem("passkeys4337.me");
setMe(null);
}

Expand All @@ -50,8 +50,8 @@ function useMeHook() {
console.log("error while saving user");
return;
}
localStorage.setItem("hocuspocus.me", JSON.stringify(me));
localStorage.setItem("hocuspocus.returning", "true");
localStorage.setItem("passkeys4337.me", JSON.stringify(me));
localStorage.setItem("passkeys4337.returning", "true");
walletConnect.smartWalletAddress = me.account;
setIsReturning(true);
setMe(me);
Expand All @@ -70,27 +70,34 @@ function useMeHook() {
return;
}
const user = await getUser(credential.rawId);

if (user?.account === undefined || user?.account === zeroAddress) {
throw new Error("user not found");
}

const me = {
keyId: user.id as Hex,
pubKey: user.pubKey,
account: user.account,
};

localStorage.setItem("hocuspocus.me", JSON.stringify(me));
localStorage.setItem("hocuspocus.returning", "true");
localStorage.setItem("passkeys4337.me", JSON.stringify(me));
localStorage.setItem("passkeys4337.returning", "true");
walletConnect.smartWalletAddress = me.account;
setIsReturning(true);
setMe(me);
} catch (e) {
localStorage.removeItem("passkeys4337.returning");
disconnect();
console.error(e);
} finally {
setIsLoading(false);
}
}

useEffect(() => {
const me = localStorage.getItem("hocuspocus.me");
const returning = localStorage.getItem("hocuspocus.returning");
const me = localStorage.getItem("passkeys4337.me");
const returning = localStorage.getItem("passkeys4337.returning");
if (me) {
try {
setMe(JSON.parse(me));
Expand Down