Skip to content

Commit 37c397e

Browse files
committed
more wip
1 parent 010009b commit 37c397e

File tree

1 file changed

+98
-6
lines changed

1 file changed

+98
-6
lines changed

packages/hypergraph/src/identity/smart-account.ts

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ export const GEOGENESIS = {
7474
},
7575
};
7676

77+
type Action = {
78+
actionTarget: Address;
79+
actionTargetSelector: Hex;
80+
actionPolicies: { policy: Address; address: Address; initData: Hex }[];
81+
};
82+
83+
// Gets the legacy Geo smart account wallet client. If the smart account returned
84+
// by this function is deployed, it means it might need to be updated to have the 7579 module installed
7785
export const getLegacySmartAccountWalletClient = async (
7886
walletClient: WalletClient,
7987
chain: Chain = GEOGENESIS,
@@ -204,6 +212,24 @@ export const isSmartAccountDeployed = async (smartAccountClient: SmartAccountCli
204212
return smartAccountClient.account.isDeployed();
205213
};
206214

215+
export const legacySmartAccountNeedsUpdate = async (
216+
smartAccountClient: SmartAccountClient,
217+
chain: Chain,
218+
rpcUrl: string,
219+
): Promise<boolean> => {
220+
if (!smartAccountClient.account) {
221+
throw new Error('Invalid smart account');
222+
}
223+
// We assume the smart account is deployed, so we just need to check if it has the 7579 module and smart sesions validator installed
224+
// TODO: call the isModuleInstalled function from the Safe7579 ABI on the
225+
// smart account, checking if the smart sessions validator is installed. This would fail
226+
// if the smart account doesn't have the 7579 module installed.
227+
return false;
228+
};
229+
230+
// Legacy Geo smart accounts (i.e. the ones that don't have the 7579 module installed)
231+
// need to be updated to have the 7579 module installed
232+
// with the ownable and smart sessions validators.
207233
export const updateLegacySmartAccount = async (smartAccountClient: SmartAccountClient) => {
208234
if (!smartAccountClient.account?.address) {
209235
throw new Error('Invalid smart account');
@@ -281,12 +307,11 @@ export const updateLegacySmartAccount = async (smartAccountClient: SmartAccountC
281307
return receipt;
282308
};
283309

284-
type Action = {
285-
actionTarget: Address;
286-
actionTargetSelector: Hex;
287-
actionPolicies: { policy: Address; address: Address; initData: Hex }[];
288-
};
289-
310+
// This is the function that the Connect app uses to create a smart session and
311+
// enable it on the smart account.
312+
// It will prompt the user to sign the message to enable the session, and then
313+
// execute the transaction to enable the session.
314+
// It will return the permissionId.
290315
export const createSmartSession = async (
291316
walletClient: WalletClient,
292317
smartAccountClient: SmartAccountClient,
@@ -457,3 +482,70 @@ export const createSmartSession = async (
457482
}
458483
return getPermissionId({ session });
459484
};
485+
486+
// This is the function that we use on the end user app to create a smart session client that can send transactions to the smart account.
487+
// The session must have previously been created by the createSmartSession function.
488+
export const getSmartSessionClient = async (
489+
smartAccountClient: SmartAccountClient,
490+
sessionPrivateKey: `0x${string}`,
491+
permissionId: Hex,
492+
chain: Chain,
493+
rpcUrl: string,
494+
) => {
495+
if (!smartAccountClient.account) {
496+
throw new Error('Invalid smart account');
497+
}
498+
const sessionDetails = {
499+
mode: SmartSessionMode.USE,
500+
permissionId,
501+
signature: getOwnableValidatorMockSignature({
502+
threshold: 1,
503+
}),
504+
};
505+
const smartSessions = getSmartSessionsValidator({});
506+
const publicClient = createPublicClient({
507+
transport: http(rpcUrl),
508+
chain,
509+
});
510+
const sessionKeyAccount = privateKeyToAccount(sessionPrivateKey);
511+
return {
512+
sendTransaction: async <const calls extends readonly unknown[]>({ calls }: { calls: calls }) => {
513+
if (!smartAccountClient.account) {
514+
throw new Error('Invalid smart account');
515+
}
516+
const account = getAccount({
517+
address: smartAccountClient.account.address,
518+
type: 'safe',
519+
});
520+
const nonce = await getAccountNonce(publicClient, {
521+
address: smartAccountClient.account.address,
522+
entryPointAddress: entryPoint07Address,
523+
key: encodeValidatorNonce({
524+
account,
525+
validator: smartSessions,
526+
}),
527+
});
528+
const userOperation = await smartAccountClient.prepareUserOperation({
529+
account: smartAccountClient.account,
530+
calls,
531+
nonce,
532+
signature: encodeSmartSessionSignature(sessionDetails),
533+
});
534+
535+
const userOpHashToSign = getUserOperationHash({
536+
chainId: chain.id,
537+
entryPointAddress: entryPoint07Address,
538+
entryPointVersion: '0.7',
539+
userOperation,
540+
});
541+
542+
sessionDetails.signature = await sessionKeyAccount.signMessage({
543+
message: { raw: userOpHashToSign },
544+
});
545+
546+
userOperation.signature = encodeSmartSessionSignature(sessionDetails);
547+
548+
return smartAccountClient.sendUserOperation(userOperation as UserOperation);
549+
},
550+
};
551+
};

0 commit comments

Comments
 (0)