Skip to content

Commit 3285392

Browse files
committed
extend with privy based app
1 parent 2e4f0f1 commit 3285392

File tree

21 files changed

+475
-99
lines changed

21 files changed

+475
-99
lines changed

apps/connect/src/routes/authenticate.tsx

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,6 @@ function AuthenticateComponent() {
336336

337337
const newAppIdentity = Connect.createAppIdentity();
338338

339-
console.log('creating smart session');
340-
console.log('public spaces data', publicSpacesData);
341339
const spaces =
342340
publicSpacesData
343341
// .filter((space) => selectedPublicSpaces.has(space.id))
@@ -348,10 +346,8 @@ function AuthenticateComponent() {
348346
: (space.mainVotingAddress as `0x${string}`),
349347
type: space.type as 'personal' | 'public',
350348
})) ?? [];
351-
console.log('spaces', spaces);
352349

353350
const localAccount = privateKeyToAccount(keys.signaturePrivateKey as `0x${string}`);
354-
console.log('local account', localAccount.address);
355351
// TODO: add additional actions (must be passed from the app)
356352
const permissionId = await Connect.createSmartSession(
357353
localAccount,
@@ -365,17 +361,14 @@ function AuthenticateComponent() {
365361
additionalActions: [],
366362
},
367363
);
368-
console.log('smart session created');
369364
const smartAccountClient = await Connect.getSmartAccountWalletClient({
370365
owner: localAccount,
371366
address: accountAddress,
372367
chain: CHAIN,
373368
rpcUrl: import.meta.env.VITE_HYPERGRAPH_RPC_URL,
374369
});
375370

376-
console.log('encrypting app identity');
377371
const { ciphertext } = await Connect.encryptAppIdentity({ ...newAppIdentity, permissionId }, keys);
378-
console.log('proving ownership');
379372
const { accountProof, keyProof } = await Identity.proveIdentityOwnership(
380373
smartAccountClient,
381374
accountAddress,

apps/privy-login-example/src/components/logout.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import { useHypergraphApp } from '@graphprotocol/hypergraph-react';
2+
import { usePrivy } from '@privy-io/react-auth';
23
import { useRouter } from '@tanstack/react-router';
34
import { Button } from './ui/button';
45

56
export function Logout() {
67
const { logout: graphLogout } = useHypergraphApp();
8+
const { logout: privyLogout } = usePrivy();
79
const router = useRouter();
810
const disconnectWallet = async () => {
11+
privyLogout();
912
graphLogout(); // needs to be called after privy logout since it triggers a re-render
1013
router.navigate({
1114
to: '/login',

apps/privy-login-example/src/routes/__root.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { Logout } from '@/components/logout';
21
import { usePrivy } from '@privy-io/react-auth';
32
import { createRootRoute, Link, Outlet, useLayoutEffect, useRouter } from '@tanstack/react-router';
43
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools';
4+
import { Logout } from '@/components/logout';
55

66
export const Route = createRootRoute({
77
component: () => {

apps/privy-login-example/src/routes/account-inbox/$inboxId.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ export const Route = createFileRoute('/account-inbox/$inboxId')({
77

88
function RouteComponent() {
99
const { inboxId } = Route.useParams();
10-
const { identity } = useHypergraphAuth();
10+
const { privyIdentity } = useHypergraphAuth();
1111
const { messages, loading, error } = useOwnAccountInbox(inboxId);
1212

1313
// Ensure we have an authenticated user
14-
if (!identity?.accountAddress) {
14+
if (!privyIdentity?.accountAddress) {
1515
return <div>Please login to view your inbox</div>;
1616
}
1717

apps/privy-login-example/src/routes/login.lazy.tsx

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { Button } from '@/components/ui/button';
2-
import { Connect, type Identity } from '@graphprotocol/hypergraph';
3-
import { ConnectedWallet, useIdentityToken, usePrivy, useWallets } from '@privy-io/react-auth';
1+
import { Connect, type Identity, PrivyAuth } from '@graphprotocol/hypergraph';
2+
import { type ConnectedWallet, useIdentityToken, usePrivy, useWallets } from '@privy-io/react-auth';
43
import { createLazyFileRoute, useRouter } from '@tanstack/react-router';
54
import { useCallback, useEffect, useState } from 'react';
65
import { createWalletClient, custom, type WalletClient } from 'viem';
6+
import { Button } from '@/components/ui/button';
77

88
const CHAIN = import.meta.env.VITE_HYPERGRAPH_CHAIN === 'geogenesis' ? Connect.GEOGENESIS : Connect.GEO_TESTNET;
99
const syncServerUri = import.meta.env.VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN;
@@ -23,7 +23,6 @@ function Login() {
2323

2424
const hypergraphLogin = useCallback(
2525
async (walletClient: WalletClient, embeddedWallet: ConnectedWallet) => {
26-
console.log('hypergraphLogin');
2726
if (!identityToken) {
2827
return;
2928
}
@@ -49,10 +48,7 @@ function Login() {
4948

5049
const rpcUrl = import.meta.env.VITE_HYPERGRAPH_RPC_URL;
5150

52-
console.log(walletClient);
53-
console.log(rpcUrl);
54-
console.log(CHAIN);
55-
await Connect.login({
51+
await PrivyAuth.login({
5652
walletClient,
5753
signer,
5854
syncServerUri,
@@ -67,14 +63,12 @@ function Login() {
6763
);
6864

6965
useEffect(() => {
70-
console.log('useEffect in login.lazy.tsx');
7166
if (
7267
!hypergraphLoginStarted && // avoid re-running the effect too often
7368
privyAuthenticated && // privy must be authenticated to run it
7469
walletsReady && // wallets must be ready to run it
7570
wallets.length > 0 // wallets must have at least one wallet to run it
7671
) {
77-
console.log('running login effect');
7872
setHypergraphLoginStarted(true);
7973
(async () => {
8074
try {
@@ -100,9 +94,11 @@ function Login() {
10094
return (
10195
<div className="flex flex-1 justify-center items-center flex-col gap-4">
10296
<Button
97+
disabled={!privyReady || privyAuthenticated}
10398
onClick={() => {
10499
privyLogin();
105100
}}
101+
className="c-button c-button--primary sm:c-button--large mt-6"
106102
>
107103
Authenticate with Privy
108104
</Button>

apps/server/src/services/connections.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type * as Mailbox from 'effect/Mailbox';
44

55
type Connection = {
66
accountAddress: string;
7-
appIdentityAddress: string;
7+
appIdentityAddress: string | undefined;
88
mailbox: Mailbox.Mailbox<Messages.ResponseMessage>;
99
subscribedSpaces: Set<string>;
1010
};
@@ -14,7 +14,7 @@ export class ConnectionsService extends Context.Tag('ConnectionsService')<
1414
{
1515
readonly registerConnection: (params: {
1616
accountAddress: string;
17-
appIdentityAddress: string;
17+
appIdentityAddress: string | undefined;
1818
mailbox: Mailbox.Mailbox<Messages.ResponseMessage>;
1919
}) => Effect.Effect<string>;
2020
readonly removeConnection: (connectionId: string) => Effect.Effect<void>;
@@ -45,7 +45,7 @@ export const layer = Effect.gen(function* () {
4545
mailbox,
4646
}: {
4747
accountAddress: string;
48-
appIdentityAddress: string;
48+
appIdentityAddress: string | undefined;
4949
mailbox: Mailbox.Mailbox<Messages.ResponseMessage>;
5050
}) {
5151
const nextId = yield* Ref.updateAndGet(connectionCounter, (n) => n + 1);

apps/server/src/services/invitations.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as IdentityService from './identity.js';
77
export class InvitationsService extends Context.Tag('InvitationsService')<
88
InvitationsService,
99
{
10-
readonly listByAppIdentity: (
10+
readonly listByAccountAddress: (
1111
appIdentityAddress: string,
1212
) => Effect.Effect<Messages.Invitation[], DatabaseService.DatabaseError>;
1313
}
@@ -18,7 +18,7 @@ const decodeSpaceState = Schema.decodeUnknownEither(SpaceEvents.SpaceState);
1818
export const layer = Effect.gen(function* () {
1919
const { use } = yield* DatabaseService.DatabaseService;
2020

21-
const listByAppIdentity = Effect.fn('listByAppIdentity')(function* (accountAddress: string) {
21+
const listByAccountAddress = Effect.fn('listByAccountAddress')(function* (accountAddress: string) {
2222
const invitations = yield* use((client) =>
2323
client.invitation.findMany({
2424
where: {
@@ -57,6 +57,6 @@ export const layer = Effect.gen(function* () {
5757
});
5858

5959
return {
60-
listByAppIdentity,
60+
listByAccountAddress,
6161
} as const;
6262
}).pipe(Layer.effect(InvitationsService), Layer.provide(DatabaseService.layer), Layer.provide(IdentityService.layer));

apps/server/src/services/spaces.ts

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export interface CreateSpaceParams {
7777
export interface GetSpaceParams {
7878
spaceId: string;
7979
accountAddress: string;
80-
appIdentityAddress: string;
80+
appIdentityAddress?: string | undefined;
8181
}
8282

8383
export interface AddAppIdentityToSpacesParams {
@@ -103,9 +103,13 @@ export class SpacesService extends Context.Tag('SpacesService')<
103103
readonly addAppIdentityToSpaces: (
104104
params: AddAppIdentityToSpacesParams,
105105
) => Effect.Effect<void, DatabaseService.DatabaseError>;
106-
readonly listByAppIdentity: (
107-
appIdentityAddress: string,
108-
) => Effect.Effect<SpaceListEntry[], DatabaseService.DatabaseError>;
106+
readonly listByAppIdentityOrAccount: ({
107+
appIdentityAddress,
108+
accountAddress,
109+
}: {
110+
appIdentityAddress?: string | undefined;
111+
accountAddress: string;
112+
}) => Effect.Effect<SpaceListEntry[], DatabaseService.DatabaseError>;
109113
readonly getSpace: (
110114
params: GetSpaceParams,
111115
) => Effect.Effect<GetSpaceResult, ResourceNotFoundError | DatabaseService.DatabaseError>;
@@ -141,6 +145,7 @@ export const layer = Effect.gen(function* () {
141145
keyBoxes: {
142146
where: {
143147
accountAddress,
148+
appIdentityAddress: null,
144149
},
145150
},
146151
},
@@ -171,16 +176,30 @@ export const layer = Effect.gen(function* () {
171176
}));
172177
});
173178

174-
const listByAppIdentity = Effect.fn('listByAppIdentity')(function* (appIdentityAddress: string) {
179+
const listByAppIdentityOrAccount = Effect.fn('listByAppIdentityOrAccount')(function* ({
180+
appIdentityAddress,
181+
accountAddress,
182+
}: {
183+
appIdentityAddress?: string | undefined;
184+
accountAddress: string;
185+
}) {
175186
return yield* use((client) =>
176187
client.space.findMany({
177-
where: {
178-
appIdentities: {
179-
some: {
180-
address: appIdentityAddress,
188+
where: appIdentityAddress
189+
? {
190+
appIdentities: {
191+
some: {
192+
address: appIdentityAddress,
193+
},
194+
},
195+
}
196+
: {
197+
members: {
198+
some: {
199+
address: accountAddress,
200+
},
201+
},
181202
},
182-
},
183-
},
184203
include: {
185204
appIdentities: {
186205
select: {
@@ -191,9 +210,15 @@ export const layer = Effect.gen(function* () {
191210
keys: {
192211
include: {
193212
keyBoxes: {
194-
where: {
195-
appIdentityAddress,
196-
},
213+
where: appIdentityAddress
214+
? {
215+
accountAddress,
216+
appIdentityAddress,
217+
}
218+
: {
219+
accountAddress,
220+
appIdentityAddress: null,
221+
},
197222
},
198223
},
199224
},
@@ -224,10 +249,15 @@ export const layer = Effect.gen(function* () {
224249
keys: {
225250
include: {
226251
keyBoxes: {
227-
where: {
228-
accountAddress,
229-
appIdentityAddress,
230-
},
252+
where: appIdentityAddress
253+
? {
254+
accountAddress,
255+
appIdentityAddress,
256+
}
257+
: {
258+
accountAddress,
259+
appIdentityAddress: null,
260+
},
231261
select: {
232262
nonce: true,
233263
ciphertext: true,
@@ -534,7 +564,7 @@ export const layer = Effect.gen(function* () {
534564

535565
return {
536566
listByAccount,
537-
listByAppIdentity,
567+
listByAppIdentityOrAccount,
538568
getSpace,
539569
createSpace,
540570
addAppIdentityToSpaces,

apps/server/src/websocket.ts

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import * as AppIdentityService from './services/app-identity.ts';
1313
import * as ConnectionsService from './services/connections.ts';
1414
import * as IdentityService from './services/identity.ts';
1515
import * as InvitationsService from './services/invitations.ts';
16+
import * as PrivyAuthService from './services/privy-auth.ts';
1617
import * as SpaceInboxService from './services/space-inbox.ts';
1718
import * as SpacesService from './services/spaces.ts';
1819
import * as UpdatesService from './services/updates.ts';
@@ -30,18 +31,34 @@ export const WebSocketLayer = HttpLayerRouter.add(
3031
const connectionsService = yield* ConnectionsService.ConnectionsService;
3132
const accountInboxService = yield* AccountInboxService.AccountInboxService;
3233
const spaceInboxService = yield* SpaceInboxService.SpaceInboxService;
34+
const appIdentityService = yield* AppIdentityService.AppIdentityService;
35+
const identityService = yield* IdentityService.IdentityService;
36+
const privyAuthService = yield* PrivyAuthService.PrivyAuthService;
3337
const responseMailbox = yield* Mailbox.make<Messages.ResponseMessage>();
3438

3539
const searchParams = HttpServerRequest.searchParamsFromURL(new URL(request.url, 'http://localhost'));
3640
const token = isArray(searchParams.token) ? searchParams.token[0] : searchParams.token;
37-
38-
if (!token) {
41+
const privyIdentityToken = isArray(searchParams['privy-identity-token'])
42+
? searchParams['privy-identity-token'][0]
43+
: searchParams['privy-identity-token'];
44+
const privyAccountAddress = isArray(searchParams['account-address'])
45+
? searchParams['account-address'][0]
46+
: searchParams['account-address'];
47+
48+
if (!token && (!privyIdentityToken || !privyAccountAddress)) {
3949
return yield* HttpServerResponse.empty({ status: 400 });
4050
}
4151

42-
const appIdentityService = yield* AppIdentityService.AppIdentityService;
43-
const identityService = yield* IdentityService.IdentityService;
44-
const { accountAddress, address } = yield* appIdentityService.getBySessionToken(token).pipe(Effect.orDie);
52+
let accountAddress: string;
53+
let address: string | undefined;
54+
if (privyIdentityToken && privyAccountAddress) {
55+
yield* privyAuthService.authenticateRequest(privyIdentityToken, privyAccountAddress).pipe(Effect.orDie);
56+
accountAddress = privyAccountAddress;
57+
} else {
58+
const result = yield* appIdentityService.getBySessionToken(token).pipe(Effect.orDie);
59+
accountAddress = result.accountAddress;
60+
address = result.address;
61+
}
4562

4663
// Register this connection
4764
const connectionId = yield* connectionsService.registerConnection({
@@ -60,14 +77,17 @@ export const WebSocketLayer = HttpLayerRouter.add(
6077
const request = yield* decodeRequestMessage(json);
6178
switch (request.type) {
6279
case 'list-spaces': {
63-
const spaces = yield* spacesService.listByAppIdentity(address);
80+
const spaces = yield* spacesService.listByAppIdentityOrAccount({
81+
appIdentityAddress: address,
82+
accountAddress,
83+
});
6484
const outgoingMessage: Messages.ResponseListSpaces = { type: 'list-spaces', spaces: spaces };
6585
// TODO: fix Messages.serialize
6686
yield* responseMailbox.offer(Messages.serializeV2(outgoingMessage));
6787
break;
6888
}
6989
case 'list-invitations': {
70-
const invitations = yield* invitationsService.listByAppIdentity(accountAddress);
90+
const invitations = yield* invitationsService.listByAccountAddress(accountAddress);
7191
const outgoingMessage: Messages.ResponseListInvitations = {
7292
type: 'list-invitations',
7393
invitations,
@@ -215,7 +235,7 @@ export const WebSocketLayer = HttpLayerRouter.add(
215235
const inviteeAccountAddress = request.event.transaction.inviteeAccountAddress;
216236

217237
// Get the updated invitation list for the invitee
218-
const invitations = yield* invitationsService.listByAppIdentity(inviteeAccountAddress);
238+
const invitations = yield* invitationsService.listByAccountAddress(inviteeAccountAddress);
219239
const invitationMessage: Messages.ResponseListInvitations = {
220240
type: 'list-invitations',
221241
invitations,
@@ -432,5 +452,6 @@ export const WebSocketLayer = HttpLayerRouter.add(
432452
.pipe(Effect.provide(IdentityService.layer))
433453
.pipe(Effect.provide(UpdatesService.layer))
434454
.pipe(Effect.provide(AccountInboxService.layer))
435-
.pipe(Effect.provide(SpaceInboxService.layer)),
455+
.pipe(Effect.provide(SpaceInboxService.layer))
456+
.pipe(Effect.provide(PrivyAuthService.layer)),
436457
);

0 commit comments

Comments
 (0)