Skip to content

Commit 9a4a364

Browse files
authored
Merge pull request #840 from LIT-Protocol/feature/node-4567-missing-addpermittedauthmethod-and-removepermittedauthmethod
Feature/node 4567 missing addpermittedauthmethod and removepermittedauthmethod
2 parents 5bf5189 + 475d495 commit 9a4a364

File tree

12 files changed

+871
-151
lines changed

12 files changed

+871
-151
lines changed
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// Run this command for this demo:
2+
// LOG_LEVEL=silent NETWORK=naga-dev bun run ./e2e/src/demo/add-permitted-address-demo.ts
3+
4+
//
5+
// This test if a PKP EOA Auth Method could add a permitted address via the PKPViemAccount
6+
//
7+
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
8+
import { nonceManager } from 'viem';
9+
import { fundAccount } from '../helper/fundAccount';
10+
import { createLitClient } from '@lit-protocol/lit-client';
11+
import {
12+
createAuthManager,
13+
storagePlugins,
14+
ViemAccountAuthenticator,
15+
} from '@lit-protocol/auth';
16+
17+
// -- Configurations
18+
const { nagaLocal } = await import('@lit-protocol/networks');
19+
const LOCAL_NETWORK_FUNDING_AMOUNT = '1';
20+
21+
// -- Master account to fund the alice(test) account
22+
const localMasterAccount = privateKeyToAccount(
23+
process.env['LOCAL_MASTER_ACCOUNT'] as `0x${string}`,
24+
{
25+
nonceManager: nonceManager,
26+
}
27+
);
28+
29+
// -- EOA Test account via Viem
30+
const aliceViemAccount = privateKeyToAccount(generatePrivateKey());
31+
32+
// -- Using the authenticator to get the Auth Data
33+
const aliceViemAccountAuthData = await ViemAccountAuthenticator.authenticate(
34+
aliceViemAccount
35+
);
36+
37+
console.log("✅ aliceViemAccountAuthData:", aliceViemAccountAuthData);
38+
39+
try {
40+
await fundAccount(aliceViemAccount, localMasterAccount, nagaLocal, {
41+
ifLessThan: LOCAL_NETWORK_FUNDING_AMOUNT,
42+
thenFundWith: LOCAL_NETWORK_FUNDING_AMOUNT,
43+
});
44+
console.log("✅ Account Funded.")
45+
} catch (e) {
46+
throw new Error("❌ Failed to fund account.")
47+
}
48+
49+
/**
50+
* ====================================
51+
* Initialise the LitClient
52+
* ====================================
53+
*/
54+
const litClient = await createLitClient({ network: nagaLocal });
55+
console.log("✅ Created Lit Client")
56+
57+
/**
58+
* ====================================
59+
* Initialise the AuthManager
60+
* ====================================
61+
*/
62+
const authManager = createAuthManager({
63+
storage: storagePlugins.localStorageNode({
64+
appName: 'my-local-testing-app',
65+
networkName: 'local-test',
66+
storagePath: './lit-auth-local',
67+
}),
68+
});
69+
console.log("✅ Created Auth Manager")
70+
71+
// Minting a new PKP
72+
const tx = await litClient.mintWithAuth({
73+
account: aliceViemAccount,
74+
authData: aliceViemAccountAuthData,
75+
scopes: ['sign-anything'],
76+
});
77+
console.log("✅ TX 1 done");
78+
console.log("ℹ️ tx:", tx)
79+
80+
const pkpInfo = tx.data;
81+
console.log("✅ pkpInfo:", pkpInfo);
82+
83+
const pkpPermissionsManagerForAliceViemAccount = await litClient.getPKPPermissionsManager({
84+
pkpIdentifier: {
85+
tokenId: pkpInfo.tokenId,
86+
},
87+
account: aliceViemAccount,
88+
});
89+
90+
console.log("✅ pkpPermissionsManagerForAliceViemAccount:", await pkpPermissionsManagerForAliceViemAccount.getPermissionsContext());
91+
92+
// check is address permitted
93+
const aliceViemAccountIsPermitted = await pkpPermissionsManagerForAliceViemAccount.isPermittedAddress({
94+
address: aliceViemAccount.address,
95+
});
96+
97+
console.log(`❗️ ${aliceViemAccount.address} is ${aliceViemAccountIsPermitted ? 'permitted' : 'NOT permitted'}`);
98+
99+
// check if pkp address is permitted
100+
const pkpIsPermitted = await pkpPermissionsManagerForAliceViemAccount.isPermittedAddress({
101+
address: pkpInfo.ethAddress,
102+
});
103+
104+
console.log(`❗️ ${pkpInfo.ethAddress} is ${pkpIsPermitted ? 'permitted' : 'NOT permitted'}`);
105+
106+
107+
const authContext = await authManager.createPkpAuthContext({
108+
authData: aliceViemAccountAuthData,
109+
pkpPublicKey: pkpInfo.pubkey,
110+
authConfig: {
111+
capabilityAuthSigs: [],
112+
expiration: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(),
113+
statement: "",
114+
domain: "",
115+
resources: [
116+
["pkp-signing", "*"],
117+
["lit-action-execution", "*"],
118+
],
119+
},
120+
litClient,
121+
});
122+
123+
console.log("authContext:", authContext);
124+
125+
const pkpViemAccount = await litClient.getPkpViemAccount({
126+
pkpPublicKey: pkpInfo.pubkey,
127+
authContext: authContext,
128+
chainConfig: nagaLocal.getChainConfig(),
129+
});
130+
131+
await fundAccount(pkpViemAccount, localMasterAccount, nagaLocal, {
132+
ifLessThan: LOCAL_NETWORK_FUNDING_AMOUNT,
133+
thenFundWith: LOCAL_NETWORK_FUNDING_AMOUNT,
134+
});
135+
136+
const pkpViemAccountPermissionsManager = await litClient.getPKPPermissionsManager({
137+
pkpIdentifier: {
138+
tokenId: pkpInfo.tokenId,
139+
},
140+
account: pkpViemAccount,
141+
});
142+
143+
try {
144+
const tx2 = await pkpViemAccountPermissionsManager.addPermittedAddress({
145+
address: "0x1234567890123456789012345678901234567890",
146+
scopes: ["sign-anything"],
147+
});
148+
console.log('tx2:', tx2)
149+
} catch (e) {
150+
throw new Error(e);
151+
}
152+
153+
console.log("✅ pkpViemAccountPermissionsManager:", await pkpViemAccountPermissionsManager.getPermissionsContext());
154+
155+
process.exit();

e2e/src/e2e.spec.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('all', () => {
3232
ctx = await init();
3333

3434
// Create PKP and custom auth contexts using helper functions
35-
alicePkpAuthContext = await createPkpAuthContext(ctx);
35+
// alicePkpAuthContext = await createPkpAuthContext(ctx);
3636
aliceCustomAuthContext = await createCustomAuthContext(ctx);
3737
} catch (e) {
3838
console.error(e);
@@ -83,29 +83,29 @@ describe('all', () => {
8383
console.log('🔐 Testing using Programmable Key Pair authentication');
8484

8585
describe('endpoints', () => {
86-
it('pkpSign', () => createPkpSignTest(ctx, () => alicePkpAuthContext)());
86+
it('pkpSign', () => createPkpSignTest(ctx, () => ctx.alicePkpAuthContext)());
8787
it('executeJs', () =>
88-
createExecuteJsTest(ctx, () => alicePkpAuthContext)());
88+
createExecuteJsTest(ctx, () => ctx.alicePkpAuthContext)());
8989
it('viewPKPsByAddress', () =>
90-
createViewPKPsByAddressTest(ctx, () => alicePkpAuthContext)());
90+
createViewPKPsByAddressTest(ctx, () => ctx.alicePkpAuthContext)());
9191
it('viewPKPsByAuthData', () =>
92-
createViewPKPsByAuthDataTest(ctx, () => alicePkpAuthContext)());
92+
createViewPKPsByAuthDataTest(ctx, () => ctx.alicePkpAuthContext)());
9393
it('pkpEncryptDecrypt', () =>
94-
createPkpEncryptDecryptTest(ctx, () => alicePkpAuthContext)());
94+
createPkpEncryptDecryptTest(ctx, () => ctx.alicePkpAuthContext)());
9595
it('encryptDecryptFlow', () =>
96-
createEncryptDecryptFlowTest(ctx, () => alicePkpAuthContext)());
96+
createEncryptDecryptFlowTest(ctx, () => ctx.alicePkpAuthContext)());
9797
it('pkpPermissionsManagerFlow', () =>
98-
createPkpPermissionsManagerFlowTest(ctx, () => alicePkpAuthContext)());
98+
createPkpPermissionsManagerFlowTest(ctx, () => ctx.alicePkpAuthContext)());
9999
});
100100

101101
describe('integrations', () => {
102102
describe('pkp viem account', () => {
103103
it('sign message', () =>
104-
createViemSignMessageTest(ctx, () => alicePkpAuthContext)());
104+
createViemSignMessageTest(ctx, () => ctx.alicePkpAuthContext)());
105105
it('sign transaction', () =>
106-
createViemSignTransactionTest(ctx, () => alicePkpAuthContext)());
106+
createViemSignTransactionTest(ctx, () => ctx.alicePkpAuthContext)());
107107
it('sign typed data', () =>
108-
createViemSignTypedDataTest(ctx, () => alicePkpAuthContext)());
108+
createViemSignTypedDataTest(ctx, () => ctx.alicePkpAuthContext)());
109109
});
110110
});
111111
});

e2e/src/helper/pkp-utils.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* PKP Utilities
3+
*
4+
* This module provides utility functions for managing Programmable Key Pairs (PKPs)
5+
* in the Lit Protocol ecosystem. It handles the common pattern of checking for
6+
* existing PKPs and creating new ones when necessary.
7+
*
8+
* Usage:
9+
* import { getOrCreatePkp } from './helper/pkp-utils';
10+
* const pkp = await getOrCreatePkp(litClient, authData, account, storagePath, networkName);
11+
*/
12+
13+
import { storagePlugins } from '@lit-protocol/auth';
14+
15+
// Configuration constants
16+
const PAGINATION_LIMIT = 5;
17+
const APP_NAME = 'my-app';
18+
const PKP_SCOPES = ['sign-anything'];
19+
20+
/**
21+
* Gets an existing PKP or creates a new one if none exists
22+
*
23+
* @param litClient - The Lit Protocol client instance
24+
* @param authData - Authentication data for the account
25+
* @param account - The account to associate with the PKP
26+
* @param storagePath - Local storage path for PKP tokens
27+
* @param networkName - Name of the network being used
28+
* @returns Promise<PKP> - The existing or newly created PKP
29+
*/
30+
export const getOrCreatePkp = async (
31+
litClient: any,
32+
authData: any,
33+
account: any,
34+
storagePath: string,
35+
networkName: string
36+
) => {
37+
// Check for existing PKPs
38+
const { pkps } = await litClient.viewPKPsByAuthData({
39+
authData,
40+
pagination: {
41+
limit: PAGINATION_LIMIT,
42+
},
43+
storageProvider: storagePlugins.localStorageNode({
44+
appName: APP_NAME,
45+
networkName,
46+
storagePath,
47+
}),
48+
});
49+
50+
// If PKP exists, return it
51+
if (pkps && pkps[0]) {
52+
return pkps[0];
53+
}
54+
55+
// Otherwise mint new PKP
56+
const mintResult = await litClient.mintWithAuth({
57+
authData,
58+
account,
59+
scopes: PKP_SCOPES,
60+
});
61+
62+
// Query again to get the newly minted PKP in the expected format
63+
const { pkps: newPkps } = await litClient.viewPKPsByAuthData({
64+
authData,
65+
pagination: {
66+
limit: PAGINATION_LIMIT,
67+
},
68+
storageProvider: storagePlugins.localStorageNode({
69+
appName: APP_NAME,
70+
networkName,
71+
storagePath,
72+
}),
73+
});
74+
75+
return newPkps[0];
76+
};

e2e/src/helper/tests/pkp-permissions-manager-flow.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,5 +109,92 @@ export const createPkpPermissionsManagerFlowTest = (
109109

110110
assert.toBe(finalAddressPermitted, initialAddressPermitted);
111111
assert.toBe(finalActionPermitted, initialActionPermitted);
112+
113+
// Test 8: Verify new addPermittedAuthMethod method exists and is callable
114+
assert.toBeDefined(pkpPermissionsManager.addPermittedAuthMethod);
115+
assert.toBe(typeof pkpPermissionsManager.addPermittedAuthMethod, 'function');
116+
117+
// Test 9: Verify new removePermittedAuthMethodScope method exists and is callable
118+
assert.toBeDefined(pkpPermissionsManager.removePermittedAuthMethodScope);
119+
assert.toBe(typeof pkpPermissionsManager.removePermittedAuthMethodScope, 'function');
120+
121+
// Test 10: Actually test addPermittedAuthMethod functionality
122+
const testAuthMethodParams = {
123+
authMethodType: 1, // EthWallet
124+
authMethodId: '0x1234567890abcdef1234567890abcdef12345678',
125+
userPubkey: '0x04abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
126+
scopes: ['sign-anything'] as const,
127+
};
128+
129+
// Get initial auth methods count
130+
const initialAuthMethods = await pkpPermissionsManager.getPermittedAuthMethods();
131+
const initialAuthMethodsCount = initialAuthMethods.length;
132+
133+
console.log('🧪 Adding test auth method...');
134+
// Add the test auth method
135+
const addAuthMethodTx = await pkpPermissionsManager.addPermittedAuthMethod(testAuthMethodParams);
136+
assert.toBeDefined(addAuthMethodTx.hash);
137+
assert.toBeDefined(addAuthMethodTx.receipt);
138+
assert.toBe(addAuthMethodTx.receipt.status, 'success');
139+
140+
// Verify the auth method was added
141+
const authMethodsAfterAdd = await pkpPermissionsManager.getPermittedAuthMethods();
142+
assert.toBe(authMethodsAfterAdd.length, initialAuthMethodsCount + 1);
143+
144+
// Find our added auth method
145+
const addedAuthMethod = authMethodsAfterAdd.find(
146+
(am) =>
147+
am.id === testAuthMethodParams.authMethodId &&
148+
Number(am.authMethodType) === testAuthMethodParams.authMethodType
149+
);
150+
assert.toBeDefined(addedAuthMethod);
151+
console.log('✅ Test auth method successfully added');
152+
153+
// Test 11: Test removePermittedAuthMethodScope functionality
154+
const testScopeParams = {
155+
authMethodType: testAuthMethodParams.authMethodType,
156+
authMethodId: testAuthMethodParams.authMethodId,
157+
scopeId: 1, // SignAnything scope
158+
};
159+
160+
console.log('🧪 Removing scope from test auth method...');
161+
// Remove a scope from the auth method
162+
const removeScopeTx = await pkpPermissionsManager.removePermittedAuthMethodScope(testScopeParams);
163+
assert.toBeDefined(removeScopeTx.hash);
164+
assert.toBeDefined(removeScopeTx.receipt);
165+
assert.toBe(removeScopeTx.receipt.status, 'success');
166+
167+
// Verify the scope was removed by checking auth method scopes
168+
const authMethodScopes = await pkpPermissionsManager.getPermittedAuthMethodScopes({
169+
authMethodType: testAuthMethodParams.authMethodType,
170+
authMethodId: testAuthMethodParams.authMethodId,
171+
scopeId: 1,
172+
});
173+
// After removing scope 1, it should return false for that specific scope
174+
assert.toBe(authMethodScopes[0], false);
175+
console.log('✅ Scope successfully removed from test auth method');
176+
177+
// Test 12: Cleanup - Remove the test auth method entirely
178+
console.log('🧹 Cleaning up test auth method...');
179+
const removeAuthMethodTx = await pkpPermissionsManager.removePermittedAuthMethod({
180+
authMethodType: testAuthMethodParams.authMethodType,
181+
authMethodId: testAuthMethodParams.authMethodId,
182+
});
183+
assert.toBeDefined(removeAuthMethodTx.hash);
184+
assert.toBeDefined(removeAuthMethodTx.receipt);
185+
assert.toBe(removeAuthMethodTx.receipt.status, 'success');
186+
187+
// Verify the auth method was removed
188+
const finalAuthMethods = await pkpPermissionsManager.getPermittedAuthMethods();
189+
assert.toBe(finalAuthMethods.length, initialAuthMethodsCount);
190+
191+
// Ensure our test auth method is no longer in the list
192+
const removedAuthMethod = finalAuthMethods.find(
193+
(am) =>
194+
am.id === testAuthMethodParams.authMethodId &&
195+
Number(am.authMethodType) === testAuthMethodParams.authMethodType
196+
);
197+
assert.toBe(removedAuthMethod, undefined);
198+
console.log('✅ Test auth method successfully cleaned up');
112199
};
113200
};

0 commit comments

Comments
 (0)