Skip to content

Commit 21f3eb7

Browse files
committed
signing and creating smart sessions work
1 parent 2e3551f commit 21f3eb7

File tree

12 files changed

+205
-136
lines changed

12 files changed

+205
-136
lines changed

apps/connect/.env.development

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN="http://localhost:3030"
1+
VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN="http://localhost:3030"
2+
VITE_HYPERGRAPH_CHAIN="geogenesis"
3+
VITE_HYPERGRAPH_API_URL="https://hypergraph-v2.up.railway.app/graphql"
4+
VITE_HYPERGRAPH_RPC_URL="https://rpc-geo-genesis-h0q2s21xx8.t.conduit.xyz"

apps/connect/.env.production

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN="https://syncserver.hypergraph.thegraph.com"
1+
VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN="https://syncserver.hypergraph.thegraph.com"
2+
VITE_HYPERGRAPH_CHAIN="geogenesis"
3+
VITE_HYPERGRAPH_API_URL="https://hypergraph-v2.up.railway.app/graphql"
4+
VITE_HYPERGRAPH_RPC_URL="https://rpc-geo-genesis-h0q2s21xx8.t.conduit.xyz"

apps/connect/src/routes/authenticate.tsx

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { CreateSpace } from '@/components/create-space';
22
import { Button } from '@/components/ui/button';
33
import { usePrivateSpaces } from '@/hooks/use-private-spaces';
44
import { type PublicSpaceData, usePublicSpaces } from '@/hooks/use-public-spaces';
5-
import { Connect, type Identity, Key, type Messages, StoreConnect, Utils } from '@graphprotocol/hypergraph';
6-
import { GEOGENESIS, GEO_TESTNET } from '@graphprotocol/hypergraph/connect/smart-account';
5+
import { Connect, Identity, Key, type Messages, StoreConnect, Utils } from '@graphprotocol/hypergraph';
6+
import { GEOGENESIS, GEO_TESTNET, getSmartAccountWalletClient } from '@graphprotocol/hypergraph/connect/smart-account';
77
import { useIdentityToken, usePrivy, useWallets } from '@privy-io/react-auth';
88
import { createFileRoute } from '@tanstack/react-router';
99
import { createStore } from '@xstate/store';
@@ -344,6 +344,7 @@ function AuthenticateComponent() {
344344
try {
345345
const privyProvider = await embeddedWallet.getEthereumProvider();
346346
const walletClient = createWalletClient({
347+
account: embeddedWallet.address as `0x${string}`,
347348
chain: CHAIN,
348349
transport: custom(privyProvider),
349350
});
@@ -365,6 +366,20 @@ function AuthenticateComponent() {
365366

366367
const newAppIdentity = Connect.createAppIdentity();
367368

369+
console.log('creating smart session');
370+
console.log('public spaces data', publicSpacesData);
371+
const spaces =
372+
publicSpacesData
373+
?.filter((space) => selectedPublicSpaces.has(space.id))
374+
.map((space) => ({
375+
address:
376+
space.type === 'personal'
377+
? (space.personalAddress as `0x${string}`)
378+
: (space.mainVotingAddress as `0x${string}`),
379+
type: space.type as 'personal' | 'public',
380+
})) ?? [];
381+
console.log('spaces', spaces);
382+
368383
// TODO: add additional actions (must be passed from the app)
369384
const permissionId = await Connect.createSmartSession(
370385
walletClient,
@@ -374,19 +389,16 @@ function AuthenticateComponent() {
374389
import.meta.env.VITE_HYPERGRAPH_RPC_URL,
375390
{
376391
allowCreateSpace: true,
377-
spaces:
378-
publicSpacesData
379-
?.filter((space) => selectedPublicSpaces.has(space.id))
380-
.map((space) => ({
381-
address:
382-
space.type === 'personal'
383-
? (space.personalAddress as `0x${string}`)
384-
: (space.mainVotingAddress as `0x${string}`),
385-
type: space.type as 'personal' | 'public',
386-
})) ?? [],
392+
spaces,
387393
additionalActions: [],
388394
},
389395
);
396+
console.log('smart session created');
397+
const smartAccountClient = await getSmartAccountWalletClient({
398+
owner: walletClient,
399+
chain: CHAIN,
400+
rpcUrl: import.meta.env.VITE_HYPERGRAPH_RPC_URL,
401+
});
390402

391403
const { ciphertext, nonce } = await Connect.encryptAppIdentity(
392404
signer,
@@ -395,7 +407,12 @@ function AuthenticateComponent() {
395407
permissionId,
396408
keys,
397409
);
398-
const { accountProof, keyProof } = await Connect.proveIdentityOwnership(signer, accountAddress, keys);
410+
const { accountProof, keyProof } = await Identity.proveIdentityOwnership(
411+
walletClient,
412+
smartAccountClient,
413+
accountAddress,
414+
keys,
415+
);
399416

400417
const message: Messages.RequestConnectCreateAppIdentity = {
401418
appId: state.appInfo.appId,
@@ -451,6 +468,7 @@ function AuthenticateComponent() {
451468

452469
const privyProvider = await embeddedWallet.getEthereumProvider();
453470
const walletClient = createWalletClient({
471+
account: embeddedWallet.address as `0x${string}`,
454472
chain: CHAIN,
455473
transport: custom(privyProvider),
456474
});

apps/connect/src/routes/login.lazy.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ function Login() {
4848

4949
const rpcUrl = import.meta.env.VITE_HYPERGRAPH_RPC_URL;
5050

51+
console.log(walletClient);
52+
console.log(rpcUrl);
53+
console.log(CHAIN);
5154
await Connect.login({ walletClient, signer, syncServerUri, storage, identityToken, rpcUrl, chain: CHAIN });
5255
},
5356
[identityToken, signMessage],
@@ -66,6 +69,7 @@ function Login() {
6669
const embeddedWallet = wallets.find((wallet) => wallet.walletClientType === 'privy') || wallets[0];
6770
const privyProvider = await embeddedWallet.getEthereumProvider();
6871
const walletClient = createWalletClient({
72+
account: embeddedWallet.address as `0x${string}`,
6973
chain: CHAIN,
7074
transport: custom(privyProvider),
7175
});
@@ -81,7 +85,7 @@ function Login() {
8185

8286
navigate({ to: '/', replace: true });
8387
} catch (error) {
84-
alert('Failed to login');
88+
console.log('Failed to login');
8589
console.error(error);
8690
}
8791
})();

apps/server/src/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,19 +194,20 @@ app.post('/connect/identity', async (req, res) => {
194194
return;
195195
}
196196
if (
197-
!Identity.verifyIdentityOwnership(
197+
!(await Identity.verifyIdentityOwnership(
198198
accountAddress,
199199
message.signaturePublicKey,
200200
message.accountProof,
201201
message.keyProof,
202202
CHAIN,
203203
RPC_URL,
204-
)
204+
))
205205
) {
206206
console.log('Ownership proof is invalid');
207207
res.status(401).send('Unauthorized');
208208
return;
209209
}
210+
console.log('Ownership proof is valid');
210211

211212
try {
212213
await createIdentity({
@@ -288,12 +289,14 @@ app.get('/connect/app-identity/:appId', async (req, res) => {
288289
const appId = req.params.appId;
289290
const appIdentity = await findAppIdentity({ accountAddress, appId });
290291
if (!appIdentity) {
292+
console.log('App identity not found');
291293
res.status(404).json({ message: 'App identity not found' });
292294
return;
293295
}
296+
console.log('App identity found');
294297
res.status(200).json({ appIdentity });
295298
} catch (error) {
296-
console.error('Error creating space:', error);
299+
console.error('Error getting app identity:', error);
297300
if (error instanceof Error && error.message === 'No Privy ID token provided') {
298301
res.status(401).json({ message: 'Unauthorized' });
299302
} else if (error instanceof Error && error.message === 'Missing Privy configuration') {
@@ -312,6 +315,7 @@ app.post('/connect/app-identity', async (req, res) => {
312315
const message = Schema.decodeUnknownSync(Messages.RequestConnectCreateAppIdentity)(req.body);
313316
const accountAddress = message.accountAddress;
314317
if (!(await isSignerForAccount(signerAddress, accountAddress))) {
318+
console.log('Signer address is not the signer for the account');
315319
res.status(401).send('Unauthorized');
316320
return;
317321
}

packages/hypergraph/src/connect/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,5 @@ export * from './identity-encryption.js';
66
export * from './login.js';
77
export * from './parse-auth-params.js';
88
export * from './parse-callback-params.js';
9-
export * from './prove-ownership.js';
109
export * from './smart-account.js';
1110
export * from './types.js';

packages/hypergraph/src/connect/login.ts

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import * as Schema from 'effect/Schema';
2+
import type { SmartAccountClient } from 'permissionless';
23
import type { Address, Chain, Hex, WalletClient } from 'viem';
4+
import { proveIdentityOwnership } from '../identity/prove-ownership.js';
35
import * as Messages from '../messages/index.js';
46
import { store } from '../store-connect.js';
57
import { loadAccountAddress, storeAccountAddress, storeKeys } from './auth-storage.js';
68
import { createIdentityKeys } from './create-identity-keys.js';
79
import { decryptIdentity, encryptIdentity } from './identity-encryption.js';
8-
import { proveIdentityOwnership } from './prove-ownership.js';
9-
import { getSmartAccountWalletClient, smartAccountNeedsUpdate, updateLegacySmartAccount } from './smart-account.js';
10+
import {
11+
type SmartAccountParams,
12+
getSmartAccountWalletClient,
13+
isSmartAccountDeployed,
14+
smartAccountNeedsUpdate,
15+
updateLegacySmartAccount,
16+
} from './smart-account.js';
1017
import type { IdentityKeys, Signer, Storage } from './types.js';
1118

1219
export async function identityExists(accountAddress: string, syncServerUri: string) {
@@ -18,14 +25,21 @@ export async function identityExists(accountAddress: string, syncServerUri: stri
1825

1926
export async function signup(
2027
signer: Signer,
28+
walletClient: WalletClient,
29+
smartAccountClient: SmartAccountClient,
2130
accountAddress: Address,
2231
syncServerUri: string,
2332
storage: Storage,
2433
identityToken: string,
2534
) {
2635
const keys = createIdentityKeys();
2736
const { ciphertext, nonce } = await encryptIdentity(signer, keys);
28-
const { accountProof, keyProof } = await proveIdentityOwnership(signer, accountAddress, keys);
37+
const { accountProof, keyProof } = await proveIdentityOwnership(
38+
walletClient,
39+
smartAccountClient,
40+
accountAddress,
41+
keys,
42+
);
2943

3044
const req: Messages.RequestConnectCreateIdentity = {
3145
keyBox: { signer: await signer.getAddress(), accountAddress, ciphertext, nonce },
@@ -105,20 +119,42 @@ export async function login({
105119
rpcUrl: string;
106120
chain: Chain;
107121
}) {
108-
const accountAddressFromStorage = (loadAccountAddress(storage) as Hex) ?? undefined;
109-
const smartAccountWalletClient = await getSmartAccountWalletClient({
122+
const accountAddressFromStorage = loadAccountAddress(storage) as Hex;
123+
const smartAccountParams: SmartAccountParams = {
110124
owner: walletClient,
111-
address: accountAddressFromStorage,
112125
rpcUrl,
113126
chain,
114-
});
127+
};
128+
if (accountAddressFromStorage) {
129+
smartAccountParams.address = accountAddressFromStorage;
130+
}
131+
const smartAccountWalletClient = await getSmartAccountWalletClient(smartAccountParams);
115132
if (!smartAccountWalletClient.account) {
116133
throw new Error('Smart account wallet client not found');
117134
}
135+
console.log('smartAccountWalletClient', smartAccountWalletClient);
136+
console.log('address', smartAccountWalletClient.account.address);
137+
console.log('is deployed', await isSmartAccountDeployed(smartAccountWalletClient));
118138
// This will prompt the user to sign a user operation to update the smart account
119139
if (await smartAccountNeedsUpdate(smartAccountWalletClient, chain, rpcUrl)) {
120140
await updateLegacySmartAccount(smartAccountWalletClient, chain, rpcUrl);
121141
}
142+
143+
// TODO: remove this once we manage to get counterfactual signatures working
144+
if (!(await isSmartAccountDeployed(smartAccountWalletClient))) {
145+
console.log('sending dummy userOp to deploy smart account');
146+
if (!walletClient.account) {
147+
throw new Error('Wallet client account not found');
148+
}
149+
const tx = await smartAccountWalletClient.sendUserOperation({
150+
calls: [{ to: walletClient.account.address, data: '0x' }],
151+
account: smartAccountWalletClient.account,
152+
});
153+
154+
console.log('tx', tx);
155+
const receipt = await smartAccountWalletClient.waitForUserOperationReceipt({ hash: tx });
156+
console.log('receipt', receipt);
157+
}
122158
const accountAddress = smartAccountWalletClient.account.address;
123159
if (accountAddressFromStorage === undefined) {
124160
storeAccountAddress(storage, accountAddress);
@@ -130,7 +166,15 @@ export async function login({
130166
};
131167
const exists = await identityExists(accountAddress, syncServerUri);
132168
if (!exists) {
133-
authData = await signup(signer, accountAddress, syncServerUri, storage, identityToken);
169+
authData = await signup(
170+
signer,
171+
walletClient,
172+
smartAccountWalletClient,
173+
accountAddress,
174+
syncServerUri,
175+
storage,
176+
identityToken,
177+
);
134178
} else {
135179
authData = await restoreKeys(signer, accountAddress, syncServerUri, storage, identityToken);
136180
}

packages/hypergraph/src/connect/prove-ownership.ts

Lines changed: 0 additions & 58 deletions
This file was deleted.

0 commit comments

Comments
 (0)