Skip to content
Closed
1 change: 1 addition & 0 deletions src/app/(setup)/setup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const SetupPage = () => {
step.containerClassname
)}
>

<div className='w-full md:w-1/2 mg:1/3 mx-auto gap-8 lg:gap-12 h-full flex flex-col'>
<div className="flex h-[100px] flex-col gap-4">
<h1 className="text-center text-5xl font-bold">{step.title}</h1>
Expand Down
52 changes: 29 additions & 23 deletions src/context/authContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ interface AuthContextType {
updateUserName: (username: string) => Promise<void>
submitProfilePhoto: (file: File) => Promise<void>
updateBridgeCustomerId: (bridgeCustomerId: string) => Promise<void>
registerUserWithPasskey: (username: string) => Promise<void>
loginUserWithPasskey: (username: string) => Promise<void>
addAccount: ({
accountIdentifier,
accountType,
Expand All @@ -38,7 +40,6 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
// TODO: address here should be fetched from the walletContext
// TODO: all mentions of wallet in components should pull from that address
const { address } = useAccount()
const { signMessageAsync } = useSignMessage()

const { address: kernelClientAddress, isKernelClientReady, handleLogin } = useZeroDev()

Expand All @@ -62,12 +63,33 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
}
}, [user])

// TODO: this needs to be moved elsewhere (i.e. possible walletContext), was
// here for testing - POSSIBLY be removed bc the order is reversed:
// you first login w/ passkeys, so flow below would never happen
useEffect(() => {
if (kernelClientAddress != null && isKernelClientReady) {
authAndFetchUser(kernelClientAddress)
}
}, [kernelClientAddress, isKernelClientReady])

const registerUserWithPasskey = async (username: string) => {
// validatiion of @handle has happened before this function
await handleLogin(username) // TODO: replace this with handleRegister
const kernelClient = await handleLogin(username) // TODO: replace this with handleRegister
// TODO: case of failure on register
}

const loginUserWithPasskey = async (username: string) => {
// validatiion of @handle has happened before this function
const kernelClient = await handleLogin(username)
// TODO: case of failure on login
}

const authAndFetchUser = async (address: string) => {
await authUser(address)
await fetchUser()
}

const authUser = async (address: string) => {
const userIdResponse = await fetch('/api/peanut/user/get-user-id', {
method: 'POST',
headers: {
Expand All @@ -80,14 +102,9 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {

const response = await userIdResponse.json()

const siwemsg = utils.createSiweMessage({
address: address ?? '',
statement: `Sign in to peanut.to. This is your unique user identifier! ${response.userId}`,
})
const message = 'CHANGE THIS STRING WITH A MORE ROBUST THAT INCLUDES USER_ID'

const signature = await signMessageAsync({
message: siwemsg,
})
const signature = await signMessage(message)

await fetch('/api/peanut/user/get-jwt-token', {
method: 'POST',
Expand All @@ -96,29 +113,16 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
},
body: JSON.stringify({
signature: signature,
message: siwemsg,
message: message,
}),
})


// TODO: handle case where they try to register w/ pre-registered passkey
}


// TODO: document better
// used after register too (there is a login event then too)
const afterLoginUserSetup = async (): Promise<undefined> => {
// set isAuthed
setIsAuthed(true)

//TODO: REMOVE THIS - ONLY FOR TESTING
await handleLogin('hey2')

// // fetch user wallets
// // set PW as active wallet
// setupWalletsAfterLogin()


}


Expand Down Expand Up @@ -356,6 +360,8 @@ export const AuthProvider = ({ children }: { children: ReactNode }) => {
fetchUser,
updateUserName,
submitProfilePhoto,
loginUserWithPasskey,
registerUserWithPasskey,
addAccount,
isFetchingUser,
logoutUser,
Expand Down
49 changes: 14 additions & 35 deletions src/context/walletContext/walletContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ const WalletContext = createContext<WalletContextType | undefined>(undefined)

// TODO: change description
/**
* Context provider to manage user authentication and profile interactions.
* It handles fetching the user profile, updating user details (e.g., username, profile photo),
* adding accounts and logging out. It also provides hooks for child components to access user data and auth-related functions.
*
*
*
*/
export const WalletProvider = ({ children }: { children: ReactNode }) => {
////// ZeroDev props
Expand All @@ -40,39 +40,18 @@ export const WalletProvider = ({ children }: { children: ReactNode }) => {
const [selectedWallet, setSelectedWallet] = useState<interfaces.IWallet | undefined>(undefined) // TODO: this is the var that should be exposed for the app to consume, instead of const { address } = useAccount() anywhere

////// Wallets
const { data: wallets } = useQuery({
queryKey: ["wallets", user?.user.userId, kernelClientAddress, wagmiAddress],
const { data: wallets } = useQuery<interfaces.IWallet[]>({
queryKey: ["wallets", user?.user.userId],
queryFn: async () => {
/**
* TODO: fetch wallets from backend
* TODO: 2: Remove fetch & pass user?.account ?
*/
const localPasskeys = PasskeyStorage.list()
// const walletsResponse = await fetch('/api/peanut/user/get-wallets')
// if (walletsResponse.ok) {
// // receive in backend format
// const { dbWallets }: { dbWallets: interfaces.IDBWallet[] } = await walletsResponse.json()
// // manipulate to frontend format (add connected attribute)
// const wallets: interfaces.IWallet[] = dbWallets.map((dbWallet: interfaces.IDBWallet) => ({
// ...dbWallet,
// connected: false // this property will be processed into accurate values later in the flow
// }))
// }
return [
// {
// walletProviderType: interfaces.WalletProviderType.BYOW,
// protocolType: interfaces.WalletProtocolType.EVM,
// connected: false,
// address: '0x7D4c7063E003CeB8B9413f63569e7AB968AF3714'
// },
...localPasskeys.map(({ handle, account }) => ({
walletProviderType: interfaces.WalletProviderType.PEANUT,
protocolType: interfaces.WalletProtocolType.EVM,
connected: false,
address: account,
handle
}))
]
const processedWallets = user?.accounts.filter(
account => Object.values(interfaces.WalletProviderType).includes(account.account_type)
).map(account=> ({
walletProviderType: account.account_type,
protocolType: account.chain,
address: account.account_identifier,
connected: false
}))
return processedWallets ? processedWallets : []
}
})

Expand Down
22 changes: 17 additions & 5 deletions src/context/walletContext/zeroDevContext.context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ interface ZeroDevContextType {
setIsLoggingIn: (loggingIn: boolean) => void
isSendingUserOp: boolean
setIsSendingUserOp: (sendingUserOp: boolean) => void
handleRegister: (handle: string) => Promise<AppSmartAccountClient>
handleLogin: (handle: string) => Promise<void>
handleRegister: (username: string) => Promise<AppSmartAccountClient>
handleLogin: (username: string) => Promise<AppSmartAccountClient>
signMessage: (message: any) => Promise<string>
handleSendUserOpEncoded: (
{
to,
Expand Down Expand Up @@ -144,7 +145,6 @@ export const ZeroDevProvider = ({ children }: { children: ReactNode }) => {
setKernelClient(kernelClient)
setAddress(kernelClient.account!.address)
setIsKernelClientReady(true)

return kernelClient
}

Expand Down Expand Up @@ -180,7 +180,7 @@ export const ZeroDevProvider = ({ children }: { children: ReactNode }) => {

////// Login functions
//
const handleLogin = async (handle: string) => {
const handleLogin = async (handle: string): Promise<AppSmartAccountClient | undefined> => {
setIsLoggingIn(true)
try {

Expand All @@ -198,19 +198,30 @@ export const ZeroDevProvider = ({ children }: { children: ReactNode }) => {
validatorContractVersion: PasskeyValidatorContractVersion.V0_0_2
})

await createKernelClient(passkeyValidator)
const client = await createKernelClient(passkeyValidator)

setIsLoggingIn(false)

return client

} catch (e) {
toast.error('Error logging in. Please try again.')
} finally {
setIsLoggingIn(false)
return undefined
}
}


////// UserOp functions
//

const signMessage = async (message: any) => {
return kernelClient!.account!.signMessage({
message
})
}

// TODO: better docstrings
// used when data is already encoded from Peanut
// but remains unsigned
Expand Down Expand Up @@ -316,6 +327,7 @@ export const ZeroDevProvider = ({ children }: { children: ReactNode }) => {
isSendingUserOp, setIsSendingUserOp,
handleRegister,
handleLogin,
signMessage,
handleSendUserOpEncoded,
handleSendUserOpNotEncoded,
address
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ interface Account {
referrer: string | null
referred_users_points: number
totalReferralPoints: number
chain: string
}

export interface IUserProfile {
Expand Down