Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions local-tests/tests/wrapped-keys/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import type {

const emptyLitActionRepositoryCommon: LitActionCodeRepositoryCommon = {
batchGenerateEncryptedKeys: '',

// bespoke
tria_batchGenerateEncryptedKeys: '',
};

const emptyLitActionRepository: LitActionCodeRepository = {
Expand Down
13 changes: 13 additions & 0 deletions packages/types/src/lib/ILitNodeClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
RejectedNodePromises,
SendNodeCommand,
SuccessNodePromises,
GetLitActionSessionSigs,
SessionSigsMap,
} from './interfaces';
import { ILitResource, ISessionCapabilityObject } from './models';
import { SupportedJsonRequests } from './types';
Expand Down Expand Up @@ -227,4 +229,15 @@ export interface ILitNodeClient {
generateSessionCapabilityObjectWithWildcards(
litResources: ILitResource[]
): Promise<ISessionCapabilityObject>;

/**
* Retrieves session signatures specifically for Lit Actions.
* Unlike `getPkpSessionSigs`, this function requires either `litActionCode` or `litActionIpfsId`, and `jsParams` must be provided.
*
* @param params - The parameters required for retrieving the session signatures.
* @returns A promise that resolves with the session signatures.
*/
getLitActionSessionSigs(
params: GetLitActionSessionSigs
): Promise<SessionSigsMap>
}
6 changes: 6 additions & 0 deletions packages/wrapped-keys-lit-actions/esbuild.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ const wrapIIFEInStringPlugin = {
result.outputFiles.forEach((outputFile) => {
let content = outputFile.text;

const fileName = path.basename(outputFile.path);

// Use JSON.stringify to safely encode the content
const wrappedContent = `/**
* ${fileName}
* DO NOT EDIT THIS FILE. IT IS GENERATED ON BUILD. RUN \`yarn generate-lit-actions\` IN THE ROOT DIRECTORY TO UPDATE THIS FILE.
* @type {string}
*/
Expand Down Expand Up @@ -58,6 +61,9 @@ module.exports = {
'./src/lib/ethereum/generateEncryptedEthereumPrivateKey.js',
'./src/lib/common/exportPrivateKey.js',
'./src/lib/common/batchGenerateEncryptedKeys.js',

// bespoke
'./src/lib/common/bespoke/tria_batchGenerateEncryptedKeys.js',
],
bundle: true,
minify: true,
Expand Down
3 changes: 2 additions & 1 deletion packages/wrapped-keys-lit-actions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"genReact": false
},
"scripts": {
"generate-lit-actions": "yarn node ./esbuild.config.js"
"generate-lit-actions": "yarn node ./esbuild.config.js",
"sync": "yarn node sync-actions-to-ipfs.js"
},
"version": "6.9.0",
"main": "./dist/src/index.js",
Expand Down
7 changes: 7 additions & 0 deletions packages/wrapped-keys-lit-actions/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as batchGenerateEncryptedKeys from './generated/common/batchGenerateEncryptedKeys';
import * as tria_batchGenerateEncryptedKeys from './generated/common/bespoke/tria_batchGenerateEncryptedKeys';
import * as exportPrivateKey from './generated/common/exportPrivateKey';
import * as generateEncryptedEthereumPrivateKey from './generated/ethereum/generateEncryptedEthereumPrivateKey';
import * as signMessageWithEthereumEncryptedKey from './generated/ethereum/signMessageWithEncryptedEthereumKey';
Expand Down Expand Up @@ -33,6 +34,9 @@ const litActionRepository: LitActionCodeRepository = {

const litActionRepositoryCommon: LitActionCodeRepositoryCommon = {
batchGenerateEncryptedKeys: batchGenerateEncryptedKeys.code,

// bespoke
tria_batchGenerateEncryptedKeys: tria_batchGenerateEncryptedKeys.code,
};

export {
Expand All @@ -49,4 +53,7 @@ export {
// Full export to bundle all lit actions
litActionRepository,
litActionRepositoryCommon,

// bespoke
tria_batchGenerateEncryptedKeys,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
/**
* Optimization of Wrapped-Key Creation Process and Onboarding
*/
const { encryptPrivateKey } = require('./../internal/encryptKey');
const {
generateEthereumPrivateKey,
} = require('../../ethereum/internal/generatePrivateKey');
const {
signMessageEthereumKey,
} = require('../../ethereum/internal/signMessage');
const {
generateSolanaPrivateKey,
} = require('../../solana/internal/generatePrivateKey');
const { signMessageSolanaKey } = require('../../solana/internal/signMessage');

/* TRIA:: global accessControlConditions, actions, Lit*/
console.log('TRIA');
async function processEthereumAction(action) {
const { network, generateKeyParams } = action;
const messageToSign = action.signMessageParams?.messageToSign;

const ethereumKey = generateEthereumPrivateKey();

const [generatedPrivateKey, messageSignature] = await Promise.all([
encryptPrivateKey({
accessControlConditions,
publicKey: ethereumKey.publicKey,
privateKey: ethereumKey.privateKey,
}),
messageToSign
? signMessageEthereumKey({
messageToSign: messageToSign,
privateKey: ethereumKey.privateKey,
})
: Promise.resolve(),
]);

return {
network,
generateEncryptedPrivateKey: {
...generatedPrivateKey,
memo: generateKeyParams.memo,
},
...(messageSignature
? { signMessage: { signature: messageSignature } }
: {}),
};
}

async function processSolanaAction(action) {
const { network, generateKeyParams } = action;

const messageToSign = action.signMessageParams?.messageToSign;

const solanaKey = generateSolanaPrivateKey();

const [generatedPrivateKey, messageSignature] = await Promise.all([
encryptPrivateKey({
accessControlConditions,
publicKey: solanaKey.publicKey,
privateKey: solanaKey.privateKey,
}),
messageToSign
? signMessageSolanaKey({
messageToSign: messageToSign,
privateKey: solanaKey.privateKey,
})
: Promise.resolve(),
]);

return {
network,
generateEncryptedPrivateKey: {
...generatedPrivateKey,
memo: generateKeyParams.memo,
},
...(messageSignature
? { signMessage: { signature: messageSignature } }
: {}),
};
}

async function processActions(actions) {
return Promise.all(
actions.map(async (action, ndx) => {
const { network } = action;

if (network === 'evm') {
return await processEthereumAction(action, ndx);
} else if (network === 'solana') {
return await processSolanaAction(action, ndx);
} else {
// Just in case :tm:
throw new Error(`Invalid network for action[${ndx}]: ${network}`);
}
})
);
}

// (async () => {
// try {
// validateParams(actions);

// const batchGeneratePrivateKeysActionResult = await processActions(actions);

// Lit.Actions.setResponse({
// response: JSON.stringify(batchGeneratePrivateKeysActionResult),
// });

// // 1. Generate both EVM and solana private keys
// // 2. Run appropriate signMessage for each key _and_ encrypt the keys for persistence to wrapped-keys backend
// // 3. Return results for both signMessage ops and both encrypted key payloads for persistence
// } catch (err) {
// Lit.Actions.setResponse({ response: `Error: ${err.message}` });
// }
// })();

/**
* - jsParams: Expected data type: Object (e.g., "{ authMethod: { accessToken: '...', authMethodType: '...' }, publicKey: '...', actions: [...] }")
*
* This parameter is an object containing the following properties:
* - authMethod
* - publicKey
* - actions: Array of action objects, each containing network and key generation params.
*
*/
function validateJsParams(jsParams) {
if (!jsParams.authMethod) {
throw new Error('Missing required field: authMethod');
}
if (!jsParams.publicKey) {
throw new Error('Missing required field: publicKey');
}

const { accessToken, authMethodType } = jsParams.authMethod;

if (!accessToken) {
throw new Error('Missing required field: authMethod.accessToken');
}
if (!authMethodType) {
throw new Error('Missing required field: authMethod.authMethodType');
}

if (!jsParams.actions) {
throw new Error('Missing required field: actions');
}

if (!jsParams.actions.length) {
throw new Error('No actions provided (empty array?)');
}

jsParams.actions.forEach((action, ndx) => {
if (!['evm', 'solana'].includes(action.network)) {
throw new Error(
`Invalid field: actions[${ndx}].network: ${action.network}`
);
}

if (!action.generateKeyParams) {
throw new Error(
`Missing required field: actions[${ndx}].generateKeyParams`
);
}

if (!action.generateKeyParams?.memo) {
throw new Error(
`Missing required field: actions[${ndx}].generateKeyParams.memo`
);
}

if (action.signMessageParams && !action.signMessageParams?.messageToSign) {
throw new Error(
`Missing required field: actions[${ndx}].signMessageParams.messageToSign`
);
}
});
}

const go = async () => {
// Lit Action:: Prepare jsParams
const jsParams = {
authMethod: {
accessToken: authMethod.accessToken,
authMethodType: authMethod.authMethodType,
},
publicKey: publicKey,
actions: actions,
};

validateJsParams(jsParams);

// Authentication
const url = 'https://api.development.tria.so/api/v1/user/info';
const response = await fetch(url, {
method: 'GET',
headers: {
Authorization: `Bearer ${jsParams.authMethod.accessToken}`,
},
});
const data = await response.json();
console.log('data', data);

if (!data.success) {
Lit.Actions.setResponse({
response: JSON.stringify({
success: false,
message: 'Authentication Failed',
}),
});
return;
}

// Authorization:: Prepare params
// -- 1. get the authMethodId from unique identify from the response
const authMethodId = `${ethers.utils.keccak256(
ethers.utils.toUtf8Bytes(data.userInfo.uuid)
)}`;
console.log('Computed AuthMethodId', authMethodId);

// -- 2. get the PKP token id
const tokenId = Lit.Actions.pubkeyToTokenId({
publicKey: jsParams.publicKey,
});
console.log('tokenId', tokenId);

// -- 3. get the permitted auth methods of the PKP token id
const permittedAuthMethods = await Lit.Actions.getPermittedAuthMethods({
tokenId,
});
console.log('permittedAuthMethods', permittedAuthMethods);

// -- 4. only get where authMethod that's equal to the authMethod Id
const permittedAuthMethod = permittedAuthMethods.find(
(method) => method.id === authMethodId
);
console.log('permittedAuthMethod', permittedAuthMethod);

// Authorization:: Failed Authentication and Authorization
if (
!permittedAuthMethod ||
permittedAuthMethod.auth_method_type !== jsParams.authMethod.authMethodType
) {
Lit.Actions.setResponse({
response: JSON.stringify({
success: false,
message: 'Authorization Failed',
}),
});
return;
}

// Authorization:: Successful Authentication and Authorization
//LitActions.setResponse({ success: true, response: "true" });
LitActions.setResponse({
response: "(true, 'Anything your want to use in executeJs')",
});
};

go();
6 changes: 6 additions & 0 deletions packages/wrapped-keys/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {
storeEncryptedKey,
listEncryptedKeyMetadata,
batchGeneratePrivateKeys,

// bespoke
triaBatchGeneratePrivateKeys,
} from './lib/api';
import {
CHAIN_ETHEREUM,
Expand Down Expand Up @@ -71,6 +74,9 @@ export const api = {
signTransactionWithEncryptedKey,
storeEncryptedKey,
batchGeneratePrivateKeys,

// bespoke
triaBatchGeneratePrivateKeys,
};

export const config = {
Expand Down
Loading
Loading