Skip to content

Commit 4c9e791

Browse files
committed
wip: optimised batch generate keys
1 parent 39cf924 commit 4c9e791

File tree

14 files changed

+517
-11
lines changed

14 files changed

+517
-11
lines changed

local-tests/tests/wrapped-keys/util.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import type {
1515

1616
const emptyLitActionRepositoryCommon: LitActionCodeRepositoryCommon = {
1717
batchGenerateEncryptedKeys: '',
18+
19+
// bespoke
20+
tria_batchGenerateEncryptedKeys: '',
1821
};
1922

2023
const emptyLitActionRepository: LitActionCodeRepository = {

packages/types/src/lib/ILitNodeClient.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {
1818
RejectedNodePromises,
1919
SendNodeCommand,
2020
SuccessNodePromises,
21+
GetLitActionSessionSigs,
22+
SessionSigsMap,
2123
} from './interfaces';
2224
import { ILitResource, ISessionCapabilityObject } from './models';
2325
import { SupportedJsonRequests } from './types';
@@ -227,4 +229,15 @@ export interface ILitNodeClient {
227229
generateSessionCapabilityObjectWithWildcards(
228230
litResources: ILitResource[]
229231
): Promise<ISessionCapabilityObject>;
232+
233+
/**
234+
* Retrieves session signatures specifically for Lit Actions.
235+
* Unlike `getPkpSessionSigs`, this function requires either `litActionCode` or `litActionIpfsId`, and `jsParams` must be provided.
236+
*
237+
* @param params - The parameters required for retrieving the session signatures.
238+
* @returns A promise that resolves with the session signatures.
239+
*/
240+
getLitActionSessionSigs(
241+
params: GetLitActionSessionSigs
242+
): Promise<SessionSigsMap>
230243
}

packages/wrapped-keys-lit-actions/esbuild.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@ const wrapIIFEInStringPlugin = {
2525
result.outputFiles.forEach((outputFile) => {
2626
let content = outputFile.text;
2727

28+
const fileName = path.basename(outputFile.path);
29+
2830
// Use JSON.stringify to safely encode the content
2931
const wrappedContent = `/**
32+
* ${fileName}
3033
* DO NOT EDIT THIS FILE. IT IS GENERATED ON BUILD. RUN \`yarn generate-lit-actions\` IN THE ROOT DIRECTORY TO UPDATE THIS FILE.
3134
* @type {string}
3235
*/
@@ -58,6 +61,9 @@ module.exports = {
5861
'./src/lib/ethereum/generateEncryptedEthereumPrivateKey.js',
5962
'./src/lib/common/exportPrivateKey.js',
6063
'./src/lib/common/batchGenerateEncryptedKeys.js',
64+
65+
// bespoke
66+
'./src/lib/common/bespoke/tria_batchGenerateEncryptedKeys.js',
6167
],
6268
bundle: true,
6369
minify: true,

packages/wrapped-keys-lit-actions/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
"genReact": false
2525
},
2626
"scripts": {
27-
"generate-lit-actions": "yarn node ./esbuild.config.js"
27+
"generate-lit-actions": "yarn node ./esbuild.config.js",
28+
"sync": "yarn node sync-actions-to-ipfs.js"
2829
},
2930
"version": "6.9.0",
3031
"main": "./dist/src/index.js",

packages/wrapped-keys-lit-actions/src/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as batchGenerateEncryptedKeys from './generated/common/batchGenerateEncryptedKeys';
2+
import * as tria_batchGenerateEncryptedKeys from './generated/common/bespoke/tria_batchGenerateEncryptedKeys';
23
import * as exportPrivateKey from './generated/common/exportPrivateKey';
34
import * as generateEncryptedEthereumPrivateKey from './generated/ethereum/generateEncryptedEthereumPrivateKey';
45
import * as signMessageWithEthereumEncryptedKey from './generated/ethereum/signMessageWithEncryptedEthereumKey';
@@ -33,6 +34,9 @@ const litActionRepository: LitActionCodeRepository = {
3334

3435
const litActionRepositoryCommon: LitActionCodeRepositoryCommon = {
3536
batchGenerateEncryptedKeys: batchGenerateEncryptedKeys.code,
37+
38+
// bespoke
39+
tria_batchGenerateEncryptedKeys: tria_batchGenerateEncryptedKeys.code,
3640
};
3741

3842
export {
@@ -49,4 +53,7 @@ export {
4953
// Full export to bundle all lit actions
5054
litActionRepository,
5155
litActionRepositoryCommon,
56+
57+
// bespoke
58+
tria_batchGenerateEncryptedKeys,
5259
};
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
/**
2+
* Optimization of Wrapped-Key Creation Process and Onboarding
3+
*/
4+
const { encryptPrivateKey } = require('./../internal/encryptKey');
5+
const {
6+
generateEthereumPrivateKey,
7+
} = require('../../ethereum/internal/generatePrivateKey');
8+
const {
9+
signMessageEthereumKey,
10+
} = require('../../ethereum/internal/signMessage');
11+
const {
12+
generateSolanaPrivateKey,
13+
} = require('../../solana/internal/generatePrivateKey');
14+
const { signMessageSolanaKey } = require('../../solana/internal/signMessage');
15+
16+
/* TRIA:: global accessControlConditions, actions, Lit*/
17+
console.log('TRIA');
18+
async function processEthereumAction(action) {
19+
const { network, generateKeyParams } = action;
20+
const messageToSign = action.signMessageParams?.messageToSign;
21+
22+
const ethereumKey = generateEthereumPrivateKey();
23+
24+
const [generatedPrivateKey, messageSignature] = await Promise.all([
25+
encryptPrivateKey({
26+
accessControlConditions,
27+
publicKey: ethereumKey.publicKey,
28+
privateKey: ethereumKey.privateKey,
29+
}),
30+
messageToSign
31+
? signMessageEthereumKey({
32+
messageToSign: messageToSign,
33+
privateKey: ethereumKey.privateKey,
34+
})
35+
: Promise.resolve(),
36+
]);
37+
38+
return {
39+
network,
40+
generateEncryptedPrivateKey: {
41+
...generatedPrivateKey,
42+
memo: generateKeyParams.memo,
43+
},
44+
...(messageSignature
45+
? { signMessage: { signature: messageSignature } }
46+
: {}),
47+
};
48+
}
49+
50+
async function processSolanaAction(action) {
51+
const { network, generateKeyParams } = action;
52+
53+
const messageToSign = action.signMessageParams?.messageToSign;
54+
55+
const solanaKey = generateSolanaPrivateKey();
56+
57+
const [generatedPrivateKey, messageSignature] = await Promise.all([
58+
encryptPrivateKey({
59+
accessControlConditions,
60+
publicKey: solanaKey.publicKey,
61+
privateKey: solanaKey.privateKey,
62+
}),
63+
messageToSign
64+
? signMessageSolanaKey({
65+
messageToSign: messageToSign,
66+
privateKey: solanaKey.privateKey,
67+
})
68+
: Promise.resolve(),
69+
]);
70+
71+
return {
72+
network,
73+
generateEncryptedPrivateKey: {
74+
...generatedPrivateKey,
75+
memo: generateKeyParams.memo,
76+
},
77+
...(messageSignature
78+
? { signMessage: { signature: messageSignature } }
79+
: {}),
80+
};
81+
}
82+
83+
async function processActions(actions) {
84+
return Promise.all(
85+
actions.map(async (action, ndx) => {
86+
const { network } = action;
87+
88+
if (network === 'evm') {
89+
return await processEthereumAction(action, ndx);
90+
} else if (network === 'solana') {
91+
return await processSolanaAction(action, ndx);
92+
} else {
93+
// Just in case :tm:
94+
throw new Error(`Invalid network for action[${ndx}]: ${network}`);
95+
}
96+
})
97+
);
98+
}
99+
100+
// (async () => {
101+
// try {
102+
// validateParams(actions);
103+
104+
// const batchGeneratePrivateKeysActionResult = await processActions(actions);
105+
106+
// Lit.Actions.setResponse({
107+
// response: JSON.stringify(batchGeneratePrivateKeysActionResult),
108+
// });
109+
110+
// // 1. Generate both EVM and solana private keys
111+
// // 2. Run appropriate signMessage for each key _and_ encrypt the keys for persistence to wrapped-keys backend
112+
// // 3. Return results for both signMessage ops and both encrypted key payloads for persistence
113+
// } catch (err) {
114+
// Lit.Actions.setResponse({ response: `Error: ${err.message}` });
115+
// }
116+
// })();
117+
118+
/**
119+
* - jsParams: Expected data type: Object (e.g., "{ authMethod: { accessToken: '...', authMethodType: '...' }, publicKey: '...', actions: [...] }")
120+
*
121+
* This parameter is an object containing the following properties:
122+
* - authMethod
123+
* - publicKey
124+
* - actions: Array of action objects, each containing network and key generation params.
125+
*
126+
*/
127+
function validateJsParams(jsParams) {
128+
if (!jsParams.authMethod) {
129+
throw new Error('Missing required field: authMethod');
130+
}
131+
if (!jsParams.publicKey) {
132+
throw new Error('Missing required field: publicKey');
133+
}
134+
135+
const { accessToken, authMethodType } = jsParams.authMethod;
136+
137+
if (!accessToken) {
138+
throw new Error('Missing required field: authMethod.accessToken');
139+
}
140+
if (!authMethodType) {
141+
throw new Error('Missing required field: authMethod.authMethodType');
142+
}
143+
144+
if (!jsParams.actions) {
145+
throw new Error('Missing required field: actions');
146+
}
147+
148+
if (!jsParams.actions.length) {
149+
throw new Error('No actions provided (empty array?)');
150+
}
151+
152+
jsParams.actions.forEach((action, ndx) => {
153+
if (!['evm', 'solana'].includes(action.network)) {
154+
throw new Error(
155+
`Invalid field: actions[${ndx}].network: ${action.network}`
156+
);
157+
}
158+
159+
if (!action.generateKeyParams) {
160+
throw new Error(
161+
`Missing required field: actions[${ndx}].generateKeyParams`
162+
);
163+
}
164+
165+
if (!action.generateKeyParams?.memo) {
166+
throw new Error(
167+
`Missing required field: actions[${ndx}].generateKeyParams.memo`
168+
);
169+
}
170+
171+
if (action.signMessageParams && !action.signMessageParams?.messageToSign) {
172+
throw new Error(
173+
`Missing required field: actions[${ndx}].signMessageParams.messageToSign`
174+
);
175+
}
176+
});
177+
}
178+
179+
const go = async () => {
180+
// Lit Action:: Prepare jsParams
181+
const jsParams = {
182+
authMethod: {
183+
accessToken: authMethod.accessToken,
184+
authMethodType: authMethod.authMethodType,
185+
},
186+
publicKey: publicKey,
187+
actions: actions,
188+
};
189+
190+
validateJsParams(jsParams);
191+
192+
// Authentication
193+
const url = 'https://api.development.tria.so/api/v1/user/info';
194+
const response = await fetch(url, {
195+
method: 'GET',
196+
headers: {
197+
Authorization: `Bearer ${jsParams.authMethod.accessToken}`,
198+
},
199+
});
200+
const data = await response.json();
201+
console.log('data', data);
202+
203+
if (!data.success) {
204+
Lit.Actions.setResponse({
205+
response: JSON.stringify({
206+
success: false,
207+
message: 'Authentication Failed',
208+
}),
209+
});
210+
return;
211+
}
212+
213+
// Authorization:: Prepare params
214+
// -- 1. get the authMethodId from unique identify from the response
215+
const authMethodId = `${ethers.utils.keccak256(
216+
ethers.utils.toUtf8Bytes(data.userInfo.uuid)
217+
)}`;
218+
console.log('Computed AuthMethodId', authMethodId);
219+
220+
// -- 2. get the PKP token id
221+
const tokenId = Lit.Actions.pubkeyToTokenId({
222+
publicKey: jsParams.publicKey,
223+
});
224+
console.log('tokenId', tokenId);
225+
226+
// -- 3. get the permitted auth methods of the PKP token id
227+
const permittedAuthMethods = await Lit.Actions.getPermittedAuthMethods({
228+
tokenId,
229+
});
230+
console.log('permittedAuthMethods', permittedAuthMethods);
231+
232+
// -- 4. only get where authMethod that's equal to the authMethod Id
233+
const permittedAuthMethod = permittedAuthMethods.find(
234+
(method) => method.id === authMethodId
235+
);
236+
console.log('permittedAuthMethod', permittedAuthMethod);
237+
238+
// Authorization:: Failed Authentication and Authorization
239+
if (
240+
!permittedAuthMethod ||
241+
permittedAuthMethod.auth_method_type !== jsParams.authMethod.authMethodType
242+
) {
243+
Lit.Actions.setResponse({
244+
response: JSON.stringify({
245+
success: false,
246+
message: 'Authorization Failed',
247+
}),
248+
});
249+
return;
250+
}
251+
252+
// Authorization:: Successful Authentication and Authorization
253+
//LitActions.setResponse({ success: true, response: "true" });
254+
LitActions.setResponse({
255+
response: "(true, 'Anything your want to use in executeJs')",
256+
});
257+
};
258+
259+
go();

packages/wrapped-keys/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import {
88
storeEncryptedKey,
99
listEncryptedKeyMetadata,
1010
batchGeneratePrivateKeys,
11+
12+
// bespoke
13+
triaBatchGeneratePrivateKeys,
1114
} from './lib/api';
1215
import {
1316
CHAIN_ETHEREUM,
@@ -71,6 +74,9 @@ export const api = {
7174
signTransactionWithEncryptedKey,
7275
storeEncryptedKey,
7376
batchGeneratePrivateKeys,
77+
78+
// bespoke
79+
triaBatchGeneratePrivateKeys,
7480
};
7581

7682
export const config = {

0 commit comments

Comments
 (0)