Skip to content

Commit

Permalink
feat: Use low level ZeroDev SDK functions to build context from scratch
Browse files Browse the repository at this point in the history
  • Loading branch information
panosfilianos committed Oct 22, 2024
1 parent 6aeefe0 commit 5b0eb65
Show file tree
Hide file tree
Showing 5 changed files with 484 additions and 19 deletions.
211 changes: 211 additions & 0 deletions src/components/Setup/Views/Handle.provider.view.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
// Based on https://github.com/zerodevapp/passkey-tutorial/blob/7e17e287cbaaa1c2f2df53feb016e5fb0a42ac34/app/page.tsx
'use client'

// ZeroDev imports
import {
createKernelAccount,
createKernelAccountClient,
createZeroDevPaymasterClient,
KernelAccountClient
} from "@zerodev/sdk"
import {
toPasskeyValidator,
toWebAuthnKey,
WebAuthnMode,
PasskeyValidatorContractVersion
} from "@zerodev/passkey-validator"
import { KERNEL_V3_1 } from "@zerodev/sdk/constants"

// Viem imports
import { arbitrum } from 'viem/chains'
import { createPublicClient, http, parseAbi, encodeFunctionData, } from "viem"

// Permissionless imports
import { bundlerActions, ENTRYPOINT_ADDRESS_V07} from 'permissionless'

import React, { useEffect, useState } from "react"
import { UserOperation } from "viem/_types/account-abstraction/types/userOperation"
import { useZeroDev } from "@/context/walletContext/zeroDevContext.context"



// let kernelAccount: any
let kernelClient: any
let validator: any

// permissionless.js is a TS library built on top of viem to deploy, interact and manage
// ERC-4337 smart accounts, bundlers, paymasters etc.
// import { bundlerActions } from "permissionless"

// This file contains logic for an ZeroDev Account Abstraction (AA) Proof of Concept
// If you don't know what Entry Points, UserOps, ECDSA validators, Kernel clients or
// Passkey validators are, I suggest you read up on:
// - ERC-4337 docs: https://www.erc4337.io/docs
// - ZeroDev docs: https://docs.zerodev.app/

// TODO: break logic in its appropriate files

export const HandleSetupView = ({}) => {
// data related state
const [mounted, setMounted] = useState(false)
const [username, setUsername] = useState("")
const [accountAddress, setAccountAddress] = useState("")
const [userOpHash, setUserOpHash] = useState("")
const [userOpStatus, setUserOpStatus] = useState("")

const {
address,
isRegistering,
isLoggingIn,
isKernelClientReady,
isSendingUserOp,
handleLogin,
handleRegister,
handleSendUserOpNotEncoded,
} = useZeroDev()


const contractAddress = "0x34bE7f35132E97915633BC1fc020364EA5134863"
const contractABI = parseAbi([
"function mint(address _to) public",
"function balanceOf(address owner) external view returns (uint256 balance)"
])

const handleSendUserOp = async () => {
const userOpHash = await handleSendUserOpNotEncoded({
to: contractAddress,
value: 0,
abi: contractABI,
functionName: 'mint',
args: [address],
})

console.log(userOpHash)
}

// useEffect(() => {
// if (kernelAccount) {
// createZeroDevKernelAccountClient()
// }
// }, [kernelAccount]);


// useEffect(() => {
// if (kernelClient) {
// setIsKernelClientReady(true)
// setAccountAddress(kernelAccount.address)
// }
// }, [kernelClient]);

// Spinner component for visual feedback during loading states
const Spinner = () => (
<svg
className="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
)



return (
<main className="flex items-center justify-center min-h-screen px-4 py-24">
<div className="w-full max-w-lg mx-auto">
<h1 className="text-4xl font-semibold text-center mb-12">
Passkeys
</h1>

<div className="space-y-4">
{/* Account Address Label */}
{address && (
<div className="text-center mb-4">
Account address:{" "}
<a
href={`https://jiffyscan.xyz/account/${address}`}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 hover:text-blue-700"
>
{" "}
{address}{" "}
</a>
</div>
)}

{/* Input Box */}
<input
type="text"
placeholder="handle"
value={username}
onChange={(e) => setUsername(e.target.value)}
className="p-2 text-black border border-gray-300 w-full"
/>

{/* Register and Login Buttons */}
<div className="flex flex-col sm:flex-row sm:space-x-4">
{/* Register Button */}
<button
onClick={() => {
handleRegister(username)
}}
disabled={isRegistering || isLoggingIn}
className="flex justify-center items-center px-4 py-2 bg-blue-500 text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 w-full"
>
{isRegistering ? <Spinner /> : "Register"}
</button>

{/* Login Button */}
<button
onClick={() => {
handleLogin(username)
}}
disabled={isLoggingIn || isRegistering}
className="mt-2 sm:mt-0 flex justify-center items-center px-4 py-2 bg-purple-500 text-white hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-opacity-50 w-full"
>
{isLoggingIn ? <Spinner /> : "Login"}
</button>
</div>

{/* Send UserOp Button */}
<div className="flex flex-col items-center w-full">
<button
onClick={handleSendUserOp}
disabled={!isKernelClientReady || isSendingUserOp}
className={`px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-opacity-50 flex justify-center items-center w-full ${
isKernelClientReady && !isSendingUserOp
? "bg-green-500 hover:bg-green-700 focus:ring-green-500"
: "bg-gray-500"
}`}
>
{isSendingUserOp ? <Spinner /> : "Send UserOp"}
</button>
{/* UserOp Status Label */}
{userOpHash && (
<div
className="mt-4"
dangerouslySetInnerHTML={{
__html: userOpStatus
}}
/>
)}
</div>
</div>
</div>
</main>
)
}
2 changes: 1 addition & 1 deletion src/components/Setup/Views/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './Handle.waas.view'
export * from './Handle.provider.view'
6 changes: 3 additions & 3 deletions src/context/contextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import { AuthProvider } from './authContext'
import { LoadingStateContextProvider } from './loadingStates.context'
import { TokenContextProvider } from './tokenSelector.context'
import { WalletProvider } from './walletContext'
import { ZeroDevPeanutProvider } from './walletContext/zeroDevContext.context'
import { ZeroDevProvider } from './walletContext/zeroDevContext.context'

export const ContextProvider = ({ children }: { children: React.ReactNode }) => {
return (
<AuthProvider>
<ZeroDevPeanutProvider>
<ZeroDevProvider>
<WalletProvider>
<TokenContextProvider>
<LoadingStateContextProvider>{children}</LoadingStateContextProvider>
</TokenContextProvider>
</WalletProvider>
</ZeroDevPeanutProvider>
</ZeroDevProvider>

</AuthProvider>
)
Expand Down
3 changes: 2 additions & 1 deletion src/context/walletContext/walletContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useKernelClient } from "@zerodev/waas"

// TOOD: go through TODOs

// TODO: remove any unused imports
// TODO: move to context consts
interface WalletContextType {
activeWalletType: interfaces.WalletType | undefined
Expand Down Expand Up @@ -75,7 +76,7 @@ export const WalletProvider = ({ children }: { children: ReactNode }) => {

////// ZeroDev props
//
const { address: kernelClientAddress, isConnected: isKernelClientConnected } = useKernelClient()
// const { address: kernelClientAddress, isConnected: isKernelClientConnected } = useKernelClient()

////// Lifecycle hooks
//
Expand Down
Loading

0 comments on commit 5b0eb65

Please sign in to comment.