Skip to content

Commit 3131410

Browse files
authored
Candide Docs
Candide Docs
2 parents cab4fc4 + ded63d6 commit 3131410

File tree

3 files changed

+328
-2
lines changed

3 files changed

+328
-2
lines changed

docs/integrations/aa/candide.md

Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
# Candide
2+
3+
# Recover a Safe Account with Google using AbstractionKit
4+
5+
This is the second of two guides that demonstrate how to recover a Safe smart wallet using a Google account. The first guide focuses on adding the recovery method, while this guide focuses on executing the actual recovery process. We recommend starting with guide number one which can be found [here](https://docs.candide.dev/wallet/guides/recovery-with-google-using-lit/).
6+
7+
## What is AbstractionKit?
8+
AbstractionKit is a Typescript Library that enables developers to easily build on Account Abstraction, with first class support for Safe Accounts. One of the unique use cases enabled by AbstractionKit is the ability for users to add a recovery method(s) as a backup to their account in the case that they lose access to their main signing key.
9+
10+
You can combine Lit with AbstractionKit to enable a powerful social recovery experience for your users while using Smart Accounts for gas sponsorship, transaction batching, and more.
11+
12+
### Relevant Links
13+
For additional information during this guide:
14+
15+
- [How on-chain guardian recovery works](https://docs.candide.dev/wallet/plugins/recovery-with-guardians/)
16+
- [Guardian Recovery SDK Reference](https://docs.candide.dev/blog/making-accounts-recoverable/)
17+
- [Simple Recovery example on GitHub](https://github.com/candidelabs/abstractionkit/tree/experimental/examples/SafeAccountExamples/SocialRecovery)
18+
19+
### Complete Code Example
20+
If you would like to see the complete code example, you can find it [here](https://github.com/LIT-Protocol/lit-candide).
21+
22+
### Installation
23+
Install required dependencies
24+
```
25+
npm i abstractionkit@0.1.12 @lit-protocol/lit-node-client @lit-protocol/lit-auth-client @lit-protocol/constants
26+
```
27+
28+
### Configure .env file
29+
Configure the following values within the repository `.env` file:
30+
31+
```jsx
32+
// Lit
33+
LIT_API_KEY= // Request Relay Server API Key from Lit at https://forms.gle/RNZYtGYTY9BcD9MEA
34+
35+
// Candide
36+
BUNDLER_URL="https://sepolia.voltaire.candidewallet.com/rpc" // Other networks are found here: https://docs.candide.dev/wallet/bundler/rpc-endpoints
37+
PAYMASTER_URL= // Request an API key from Candide on Discord
38+
39+
// Generate a Public/Private Key
40+
OWNER_PUBLIC_ADDRESS=
41+
OWNER_PRIVATE_KEY=
42+
NEW_OWNER_PUBLIC_ADDRESS=
43+
44+
// Network Info
45+
VITE_CHAIN_ID=
46+
JSON_RPC_NODE_PROVIDER= // Get an RPC from a Node provider
47+
```
48+
49+
### Sign in with Google using Lit
50+
51+
#### Initialize the Lit Network Connection and GoogleProvider
52+
53+
- Connect to the Lit Network using LitNodeClient.
54+
- Set up the LitAuthClient for authentication.
55+
- Initialize a GoogleProvider for Google sign-in.
56+
57+
```jsx
58+
import { LitNodeClient } from "@lit-protocol/lit-node-client";
59+
import { LitAuthClient, GoogleProvider } from "@lit-protocol/lit-auth-client";
60+
import { ProviderType, LitNetwork } from "@lit-protocol/constants";
61+
62+
const initalizeClientsAndProvider = async () => {
63+
const litNodeClient = new LitNodeClient({
64+
litNetwork: LitNetwork.DatilDev,
65+
debug: true,
66+
});
67+
await litNodeClient.connect();
68+
69+
const litAuthClient = new LitAuthClient({
70+
litRelayConfig: {
71+
relayApiKey: process.env.LIT_API_KEY,
72+
},
73+
litNodeClient,
74+
});
75+
76+
console.log("Connected to Lit Node and Lit Auth Clients ✔️");
77+
78+
const provider = litAuthClient.initProvider<GoogleProvider>(
79+
ProviderType.Google,
80+
{
81+
// redirectUri: The redirect URI Lit's login server should redirect to after a successful login
82+
}
83+
);
84+
return { litNodeClient, litAuthClient, provider };
85+
};
86+
```
87+
88+
#### Authentication with Gmail
89+
90+
- Generate an AuthMethod using the GoogleProvider
91+
- Check if the user is already authenticated. If not, redirect to Google sign-in
92+
93+
```jsx
94+
import { AuthMethod } from "@lit-protocol/types";
95+
96+
const generateAuthMethod = async () => {
97+
const url = new URL(window.location.href);
98+
if (!url.searchParams.get("provider")) {
99+
console.log("Signing in with Google...");
100+
provider.signIn((url) => {
101+
window.location.href = url;
102+
});
103+
} else if (url.searchParams.get("provider") === "google") {
104+
const authMethod = await provider.authenticate();
105+
return authMethod;
106+
}
107+
};
108+
109+
const authMethod = await generateAuthMethod();
110+
if (!authMethod) {
111+
return;
112+
}
113+
Mint PKP (Programmable Key Pair)
114+
import { LitAuthClient } from "@lit-protocol/lit-auth-client";
115+
116+
const mintWithGoogle = async (authMethod) => {
117+
const pkp = await litAuthClient.mintPKPWithAuthMethods([authMethod], {
118+
addPkpEthAddressAsPermittedAddress: true
119+
});
120+
console.log("Fetched PKP", pkp);
121+
return pkp;
122+
};
123+
124+
const pkp = await mintWithGoogle(authMethod);
125+
console.log("Minted PKP ✔️");
126+
```
127+
128+
#### Get the Google Guardian Signer
129+
130+
```jsx
131+
import { PKPEthersWallet } from "@lit-protocol/pkp-ethers";
132+
import { LitAbility, LitPKPResource } from "@lit-protocol/auth-helpers";
133+
import { AuthCallbackParams } from "@lit-protocol/types";
134+
import { LIT_RPC } from "@lit-protocol/constants";
135+
136+
const authNeededCallback = async (params: AuthCallbackParams) => {
137+
console.log(`auth needed callback params`, JSON.stringify(params, null, 2));
138+
const response = await litNodeClient.signSessionKey({
139+
statement: params.statement,
140+
authMethods: [authMethod],
141+
resourceAbilityRequests: [
142+
{
143+
resource: new LitPKPResource("*"),
144+
ability: LitAbility.PKPSigning,
145+
},
146+
],
147+
expiration: params.expiration,
148+
resources: params.resources,
149+
chainId: 1,
150+
pkpPublicKey: pkp.pkpPublicKey,
151+
});
152+
return response.authSig;
153+
};
154+
155+
const guardianSigner = new PKPEthersWallet({
156+
litNodeClient,
157+
authContext: {
158+
getSessionSigsProps: {
159+
chain: "ethereum",
160+
expiration: new Date(Date.now() + 60_000 * 60).toISOString(),
161+
resourceAbilityRequests: [
162+
{
163+
resource: new LitPKPResource("*"),
164+
ability: LitAbility.PKPSigning,
165+
},
166+
],
167+
authNeededCallback: authNeededCallback,
168+
},
169+
},
170+
pkpPubKey: pkp.pkpPublicKey,
171+
rpc: LIT_RPC.CHRONICLE_YELLOWSTONE,
172+
});
173+
console.log("Created PKPEthersWallet using the PKP ✔️");
174+
```
175+
176+
### Start the Recovery Process
177+
178+
#### Initilize the Safe Account Class
179+
180+
```jsx
181+
import { SafeAccountV0_2_0 as SafeAccount } from "abstractionkit";
182+
183+
const smartAccount = SafeAccount.initializeNewAccount([ownerPublicAddress]);
184+
console.log("Smart Account Address: ", smartAccount.accountAddress);
185+
Repare The Recovery Transaction
186+
import { SocialRecoveryModule } from "abstractionkit";
187+
188+
const srm = new SocialRecoveryModule();
189+
190+
const initiateRecoveryMetaTx = srm.createConfirmRecoveryMetaTransaction(
191+
smartAccount.accountAddress,
192+
[newOwnerPublicAddress],
193+
1, // new threshold
194+
true // whether to auto-start execution of recovery
195+
);
196+
197+
let userOperationRecovery = await guardianSmartAccount.createUserOperation(
198+
[initiateRecoveryMetaTx],
199+
process.env.JSON_RPC_NODE_PROVIDER,
200+
process.env.BUNDLER_URL
201+
);
202+
```
203+
204+
#### Sponsor the Gas
205+
206+
```jsx
207+
import { CandidePaymaster } from "abstractionkit";
208+
import ethers from "ethers"
209+
210+
// Sponsor the recovery transaction using the paymaster
211+
const paymasterUrl = process.env.PAYMASTER_URL;
212+
const paymaster = new CandidePaymaster(paymasterUrl);
213+
214+
userOperationRecovery = await paymaster.createSponsorPaymasterUserOperation(
215+
userOperationRecovery,
216+
process.env.BUNDLER_URL
217+
);
218+
```
219+
220+
#### Sign and Submit UserOperation
221+
```jsx
222+
// Sign
223+
const domain = {
224+
chainId: process.env.CHAIN_ID,
225+
verifyingContract: smartAccount.safe4337ModuleAddress,
226+
};
227+
const types = SafeAccount.EIP712_SAFE_OPERATION_TYPE;
228+
// formate according to EIP712 Safe Operation Type
229+
const { sender, ...userOp } = userOperation;
230+
const safeUserOperation = {
231+
...userOp,
232+
safe: userOperation.sender,
233+
validUntil: BigInt(0),
234+
validAfter: BigInt(0),
235+
entryPoint: smartAccount.entrypointAddress,
236+
};
237+
const signature = await guardianSigner.signTypedData(domain, types, safeUserOperation);
238+
const formatedSig = SafeAccount.formatEip712SignaturesToUseroperationSignature([ownerPublicAddress], [signature]);
239+
userOperationRecovery.signature = signature;
240+
241+
// Submit
242+
const sendUserOpResponseRecovery =
243+
await guardianSmartAccount.sendUserOperation(
244+
userOperationRecovery,
245+
process.env.BUNDLER_URL
246+
);
247+
```
248+
249+
#### Monitor UserOp
250+
```jsx
251+
// Wait for receipt
252+
const userOpReceiptResultRecovery = await sendUserOpResponseRecovery.included();
253+
254+
console.log(userOpReceiptResultRecovery);
255+
```
256+
257+
### Finalize the Recovery
258+
After the grace period is over, you can finalize the recovery
259+
260+
#### Prepare the Finalization UserOp
261+
```jsx
262+
const finalizeRecoveryMetaTx = srm.createFinalizeRecoveryMetaTransaction(
263+
smartAccount.accountAddress
264+
);
265+
266+
let userOperationFinalizeRecovery = await guardianSmartAccount.createUserOperation(
267+
[finalizeRecoveryMetaTx],
268+
process.env.JSON_RPC_NODE_PROVIDER,
269+
process.env.BUNDLER_URL
270+
);
271+
```
272+
273+
#### Sponsor the Gas
274+
```jsx
275+
// Add gas sponsorship info using paymaster
276+
userOperationFinalizeRecovery = await paymaster.createSponsorPaymasterUserOperation(
277+
userOperationRecovery,
278+
process.env.BUNDLER_URL
279+
);
280+
```
281+
282+
#### Sign and Submit
283+
```jsx
284+
// Sign userOperation
285+
const domain = {
286+
chainId: process.env.CHAIN_ID,
287+
verifyingContract: smartAccount.safe4337ModuleAddress,
288+
};
289+
290+
const types = SafeAccount.EIP712_SAFE_OPERATION_TYPE;
291+
292+
// formate according to EIP712 Safe Operation Type
293+
const { sender, ...userOp } = userOperation;
294+
const safeUserOperation = {
295+
...userOp,
296+
safe: userOperation.sender,
297+
validUntil: BigInt(0),
298+
validAfter: BigInt(0),
299+
entryPoint: smartAccount.entrypointAddress,
300+
};
301+
302+
const signature = await guardianSigner.signTypedData(domain, types, safeUserOperation);
303+
const formatedSig = SafeAccount.formatEip712SignaturesToUseroperationSignature([ownerPublicAddress], [signature]);
304+
305+
userOperationRecovery.signature = signature;
306+
307+
308+
// Submit userOperation
309+
const sendUserOperationResponseRecovery = await guardianSmartAccount.sendUserOperation(
310+
userOperationRecovery,
311+
process.env.BUNDLER_URL
312+
);
313+
```
314+
315+
#### Monitor UserOperation
316+
317+
```jsx
318+
const userOperationReceiptResultRecovery = await sendUserOperationResponseRecovery.included();
319+
320+
console.log(userOperationReceiptResultRecovery);
321+
```
322+
That's it! You've successfully recovered an account with a Google Account using Lit.
323+
324+
Find here the complete [doc page for Account Recovery](https://docs.candide.dev/wallet/plugins/recovery-with-guardians/).

docs/integrations/aa/overview.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ AA providers like Alchemy, Biconomy, and Pimlico are pioneering smart account te
5151

5252
| Provider | Description | Link to Guide |
5353
| --- | --- | --- |
54-
| [Account Kit by Alchemy](https://accountkit.alchemy.com/) | Combining Lit Protocol's pkp wallet with Account Kit allows you to use your Programmable Key Pairs (PKPs) as a smart account for your users. | [guide](../aa/alchemy-account-kit.md) |
55-
| [Pimlico](https://www.pimlico.io/) | This how-to guide will walk you through the steps to integrate Lit Protocol's OTP sign-in with email, SMS, and Whatsapp with a smart account whose user operations are relayed and sponsored by Pimlico. | [guide](../aa/pimlico.md) |
54+
| [Account Kit by Alchemy](https://accountkit.alchemy.com/) | Combining Lit Protocol's pkp wallet with Account Kit allows you to use your Programmable Key Pairs (PKPs) as a smart account for your users. | [guide](./alchemy-account-kit.md) |
55+
| [Pimlico](https://www.pimlico.io/) | This how-to guide will walk you through the steps to integrate Lit Protocol's OTP sign-in with email, SMS, and Whatsapp with a smart account whose user operations are relayed and sponsored by Pimlico. | [guide](./pimlico.md) |
56+
| [Candide Account Abstraction](https://www.candide.dev/) | This guide will walk you through the steps to integrate Lit Protocol's Google OAuth to mint a Programmable Key Pair (PKP) and use it to enable an email/social recovery flow with Candide's account abstraction provider. | [guide](./candide.md)
5657
| - | If you are an AA provider, reach out to the Lit developement team to be included! | [Reach out to the team](https://docs.google.com/forms/d/e/1FAIpQLScBVsg-NhdMIC1H1mozh2zaVX0V4WtmEPSPrtmqVtnj_3qqNw/viewform) |
5758

5859

sidebars.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ const sidebars = {
450450
'integrations/aa/alchemy-account-kit',
451451
'integrations/aa/pimlico',
452452
'integrations/aa/openfort',
453+
'integrations/aa/candide',
453454
],
454455
},
455456
{

0 commit comments

Comments
 (0)