Skip to content

Commit 8d32288

Browse files
committed
fake it till you make it (on testnet)
1 parent bd4d67f commit 8d32288

File tree

2 files changed

+89
-9
lines changed

2 files changed

+89
-9
lines changed

packages/hypergraph/src/connect/abis.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,27 @@ export const safeModuleManagerAbi = [
3333
},
3434
];
3535

36+
export const safeOwnerManagerAbi = [
37+
{
38+
inputs: [
39+
{
40+
internalType: 'address',
41+
name: 'owner',
42+
type: 'address',
43+
},
44+
{
45+
internalType: 'uint256',
46+
name: 'threshold',
47+
type: 'uint256',
48+
},
49+
],
50+
name: 'addOwnerWithThreshold',
51+
outputs: [],
52+
stateMutability: 'nonpayable',
53+
type: 'function',
54+
},
55+
];
56+
3657
// We only use this for revokeEnableSignature to use as a noop when creating a smart session
3758
export const smartSessionsAbi = [
3859
{

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

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ import {
3131
type AbiFunction,
3232
type Account,
3333
type Address,
34+
type Calls,
3435
type Chain,
3536
ContractFunctionExecutionError,
3637
type Hex,
38+
type Narrow,
3739
type SignableMessage,
3840
type WalletClient,
3941
createPublicClient,
@@ -57,6 +59,7 @@ import {
5759
personalSpaceAdminAbi,
5860
safe7579Abi,
5961
safeModuleManagerAbi,
62+
safeOwnerManagerAbi,
6063
smartSessionsAbi,
6164
} from './abis.js';
6265

@@ -171,11 +174,13 @@ export type SmartSessionClient = {
171174
// by this function is deployed, it means it might need to be updated to have the 7579 module installed
172175
const getLegacySmartAccountWalletClient = async ({
173176
owner,
177+
address,
174178
chain = GEOGENESIS,
175179
rpcUrl = DEFAULT_RPC_URL,
176180
apiKey = DEFAULT_API_KEY,
177181
}: {
178182
owner: WalletClient | Account;
183+
address?: Hex;
179184
chain?: Chain;
180185
rpcUrl?: string;
181186
apiKey?: string;
@@ -186,21 +191,19 @@ const getLegacySmartAccountWalletClient = async ({
186191
chain,
187192
});
188193

189-
console.log('owner', owner);
190-
console.log('publicClient', publicClient);
191-
console.log('chain', chain);
192-
console.log('rpcUrl', rpcUrl);
193-
console.log('apiKey', apiKey);
194-
const safeAccount = await toSafeSmartAccount({
194+
const safeAccountParams: ToSafeSmartAccountParameters<'0.7', Hex> = {
195195
client: publicClient,
196196
owners: [owner],
197197
entryPoint: {
198-
// optional, defaults to 0.7
199198
address: entryPoint07Address,
200199
version: '0.7',
201200
},
202201
version: '1.4.1',
203-
});
202+
};
203+
if (address) {
204+
safeAccountParams.address = address;
205+
}
206+
const safeAccount = await toSafeSmartAccount(safeAccountParams);
204207

205208
const bundlerTransport = http(`${BUNDLER_TRANSPORT_URL_BASE}${chain.id}/rpc?apikey=${apiKey}`);
206209
const paymasterClient = createPimlicoClient({
@@ -343,6 +346,16 @@ export const getSmartAccountWalletClient = async ({
343346
rpcUrl = DEFAULT_RPC_URL,
344347
apiKey = DEFAULT_API_KEY,
345348
}: SmartAccountParams): Promise<SmartAccountClient> => {
349+
if (chain.id === GEO_TESTNET.id) {
350+
// We don't have the smart sessions module deployed on testnet yet, so we need to use the legacy smart account wallet client
351+
// TODO: remove this once we have the smart sessions module deployed on testnet
352+
const params: SmartAccountParams = { owner, chain, rpcUrl, apiKey };
353+
if (address) {
354+
params.address = address;
355+
}
356+
console.log('on testnet, getting legacy smart account wallet client');
357+
return getLegacySmartAccountWalletClient(params);
358+
}
346359
if (address) {
347360
return get7579SmartAccountWalletClient({ owner, address, chain, rpcUrl, apiKey });
348361
}
@@ -412,6 +425,11 @@ export const smartAccountNeedsUpdate = async (
412425
chain: Chain,
413426
rpcUrl: string,
414427
): Promise<boolean> => {
428+
if (chain.id === GEO_TESTNET.id) {
429+
// We don't have the smart sessions module deployed on testnet yet, so we need to use the legacy smart account wallet client
430+
// TODO: remove this once we have the smart sessions module deployed on testnet
431+
return false;
432+
}
415433
// If we haven't deployed the smart account, we would always deploy an updated version
416434
if (!(await isSmartAccountDeployed(smartAccountClient))) {
417435
return false;
@@ -430,6 +448,12 @@ export const updateLegacySmartAccount = async (
430448
if (!smartAccountClient.account?.address) {
431449
throw new Error('Invalid smart account');
432450
}
451+
if (chain.id === GEO_TESTNET.id) {
452+
// We don't have the smart sessions module deployed on testnet yet, so we need to use the legacy smart account wallet client
453+
// TODO: remove this once we have the smart sessions module deployed on testnet
454+
console.log('on testnet, skipping updateLegacySmartAccount');
455+
return;
456+
}
433457
const ownableValidator = getOwnableValidator({
434458
owners: [smartAccountClient.account.address],
435459
threshold: 1,
@@ -596,6 +620,33 @@ export const createSmartSession = async (
596620
transport,
597621
chain,
598622
});
623+
if (chain.id === GEO_TESTNET.id) {
624+
// We don't have the smart sessions module deployed on testnet yet, so we need to fake it by adding an account owner
625+
// TODO: remove this once we have the smart sessions module deployed on testnet
626+
console.log('on testnet, faking a smart session by adding an account owner');
627+
const tx = await smartAccountClient.sendUserOperation({
628+
calls: [
629+
{
630+
to: smartAccountClient.account.address,
631+
data: encodeFunctionData({
632+
abi: safeOwnerManagerAbi,
633+
functionName: 'addOwnerWithThreshold',
634+
args: [sessionKeyAccount.address, BigInt(1)],
635+
}),
636+
value: BigInt(0),
637+
},
638+
],
639+
account: smartAccountClient.account,
640+
});
641+
const receipt = await smartAccountClient.waitForUserOperationReceipt({
642+
hash: tx,
643+
});
644+
if (!receipt.success) {
645+
throw new Error('Transaction to add account owner failed');
646+
}
647+
console.log('account owner added');
648+
return bytesToHex(randomBytes(32)) as Hex;
649+
}
599650
// We create a dummy action so that we can execute a userOp immediately and create the session onchain,
600651
// rather than having to pass along all the enable data to the end user app.
601652
// In the future, if we enable attestations with the Rhinestone registry, we can remove this and instead
@@ -768,7 +819,7 @@ export const getSmartSessionClient = async ({
768819
}): Promise<SmartSessionClient> => {
769820
const sessionKeyAccount = privateKeyToAccount(sessionPrivateKey);
770821
const smartAccountClient = await getSmartAccountWalletClient({
771-
owner: sessionKeyAccount, // Won't really be used, but we need to pass in an account
822+
owner: sessionKeyAccount, // Won't really be used (except in testnet), but we need to pass in an account
772823
address: accountAddress,
773824
chain,
774825
rpcUrl,
@@ -786,6 +837,14 @@ export const getSmartSessionClient = async ({
786837
if (!smartAccountClient.account) {
787838
throw new Error('Invalid smart account');
788839
}
840+
if (chain.id === GEO_TESTNET.id) {
841+
// We don't have the smart sessions module deployed on testnet yet, so we need to use the legacy smart account wallet client
842+
// TODO: remove this once we have the smart sessions module deployed on testnet
843+
return smartAccountClient.sendUserOperation({
844+
calls: calls as Calls<Narrow<calls>>,
845+
account: smartAccountClient.account,
846+
});
847+
}
789848
const account = getAccount({
790849
address: smartAccountClient.account.address,
791850
type: 'safe',

0 commit comments

Comments
 (0)