Skip to content

Commit 939f33d

Browse files
committed
✨ feat(demos): remove local wallet dependency from taco-aa-signing demo
- Add createViemTacoAccount utility to wrap TACo signers as Viem accounts - Replace localAccount parameter with TACo-wrapped account in smart account creation - Update function signature to eliminate private key requirement for signatory - Improve type safety by replacing explicit 'any' types where possible - Add ESLint exemptions for necessary type casts due to library incompatibilities Resolves nucypher#699: AA demo now works without local wallet, making it AI agent ready
1 parent c874f8d commit 939f33d

File tree

2 files changed

+51
-10
lines changed

2 files changed

+51
-10
lines changed

demos/taco-aa-signing/src/index.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import {
2626
import { privateKeyToAccount } from 'viem/accounts';
2727
import { sepolia } from 'viem/chains';
2828

29+
import { createViemTacoAccount } from './taco-account';
30+
2931
dotenv.config();
3032

3133
const SEPOLIA_CHAIN_ID = 11155111;
@@ -35,7 +37,6 @@ const AA_VERSION = 'mdt';
3537

3638
async function createTacoSmartAccount(
3739
publicClient: PublicClient,
38-
localAccount: ReturnType<typeof privateKeyToAccount>,
3940
provider: ethers.providers.JsonRpcProvider,
4041
) {
4142
await initialize();
@@ -49,21 +50,26 @@ async function createTacoSmartAccount(
4950
TACO_DOMAIN,
5051
COHORT_ID,
5152
);
52-
const signers = participants.map((p: any) => p.operator as Address).sort();
53+
const signers = participants.map((p) => p.operator as Address).sort();
54+
55+
// Create a TACo account using the first signer as placeholder address
56+
// This satisfies MetaMask's signatory requirement without using a local wallet
57+
const tacoAccount = createViemTacoAccount(signers[0]);
5358

5459
const smartAccount = await toMetaMaskSmartAccount({
55-
client: publicClient as any,
60+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
61+
client: publicClient as any, // Required due to viem/delegation-toolkit type incompatibilities
5662
implementation: Implementation.MultiSig,
5763
deployParams: [signers, BigInt(threshold)],
5864
deploySalt: '0x' as `0x${string}`,
59-
signatory: [{ account: localAccount }],
65+
signatory: [{ account: tacoAccount }],
6066
});
6167

6268
return { smartAccount, threshold };
6369
}
6470

6571
async function signUserOpWithTaco(
66-
userOp: any,
72+
userOp: Record<string, unknown>,
6773
provider: ethers.providers.JsonRpcProvider,
6874
) {
6975
const signingContext =
@@ -146,7 +152,6 @@ async function main() {
146152
console.log('🔧 Creating TACo smart account...\n');
147153
const { smartAccount, threshold } = await createTacoSmartAccount(
148154
publicClient,
149-
localAccount,
150155
provider,
151156
);
152157
console.log(`✅ Smart account created: ${smartAccount.address}`);
@@ -188,7 +193,8 @@ async function main() {
188193
],
189194
...fee,
190195
verificationGasLimit: BigInt(500_000),
191-
} as any);
196+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
197+
} as any); // Required due to viem/delegation-toolkit type incompatibilities
192198
console.log(
193199
`💸 Transfer amount: ${ethers.utils.formatEther(transferAmount)} ETH\n`,
194200
);
@@ -203,7 +209,8 @@ async function main() {
203209
const userOpHash = await bundlerClient.sendUserOperation({
204210
...userOp,
205211
signature: signature.aggregatedSignature as `0x${string}`,
206-
} as any);
212+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
213+
} as any); // Required due to viem/delegation-toolkit type incompatibilities
207214
console.log(`📝 UserOp Hash: ${userOpHash}`);
208215

209216
const { receipt } = await bundlerClient.waitForUserOperationReceipt({
@@ -218,8 +225,9 @@ async function main() {
218225
await logBalances(provider, localAccount.address, smartAccount.address);
219226
console.log('✨ Demo completed successfully! ✨');
220227
process.exit(0);
221-
} catch (error: any) {
222-
console.error(`❌ Demo failed: ${error.message}`);
228+
} catch (error: unknown) {
229+
const errorMessage = error instanceof Error ? error.message : String(error);
230+
console.error(`❌ Demo failed: ${errorMessage}`);
223231
process.exit(1);
224232
}
225233
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { type Address } from 'viem';
2+
import { toAccount } from 'viem/accounts';
3+
4+
/**
5+
* Creates a minimal Viem Account that serves as a placeholder for the MetaMask Smart Account.
6+
* This account is never actually used for signing - all real signing happens through the TACo network
7+
* via the separate signUserOpWithTaco function.
8+
*
9+
* @param cohortAddress - Address of a TACo cohort participant (used as the account address)
10+
* @returns A Viem Account with stub implementations
11+
*/
12+
export function createViemTacoAccount(cohortAddress: Address) {
13+
return toAccount({
14+
address: cohortAddress,
15+
16+
// These methods are never called by the MetaMask Smart Account
17+
// They only need to exist to satisfy the Account interface
18+
async signMessage() {
19+
return '0x' as `0x${string}`;
20+
},
21+
22+
async signTransaction() {
23+
return '0x' as `0x${string}`;
24+
},
25+
26+
async signTypedData() {
27+
return '0x' as `0x${string}`;
28+
},
29+
});
30+
}
31+
32+
// Legacy alias - kept for backward compatibility if needed
33+
export const createTacoAccount = createViemTacoAccount;

0 commit comments

Comments
 (0)