Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ LOCAL_MASTER_ACCOUNT=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf
NETWORK=<network-name> pnpm run test:e2e all
```

### Run a custom ticket spec

Run a single test file by pointing `--runTestsByPath` at the spec you are iterating on:

```bash
pnpm test:custom -- --runTestsByPath packages/e2e/src/tickets/drel1157-la-decryptandcombine.spec.ts
```

# Running it against a local network

## Required Environment Variables
Expand Down
29 changes: 16 additions & 13 deletions packages/e2e/src/e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { createCustomAuthContext } from './helper/auth-contexts';
import {
createCustomAuthContext,
createPkpAuthContext,
} from './helper/auth-contexts';
import {
createExecuteJsTest,
createPkpSignTest,
createPkpEncryptDecryptTest,
createEncryptDecryptFlowTest,
createPkpPermissionsManagerFlowTest,
createEoaNativeAuthFlowTest,
createExecuteJsDecryptAndCombineTest,
createExecuteJsBasicTest,
createPaymentDelegationFlowTest,
createPaymentManagerFlowTest,
createPkpEncryptDecryptTest,
createPkpPermissionsManagerFlowTest,
createPkpSignTest,
createViemSignMessageTest,
createViemSignTransactionTest,
createViemSignTypedDataTest,
createViewPKPsByAddressTest,
createViewPKPsByAuthDataTest,
createPaymentManagerFlowTest,
createPaymentDelegationFlowTest,
} from './helper/tests';
import { init } from './init';
import { AuthContext } from './types';
Expand Down Expand Up @@ -56,7 +54,12 @@ describe('all', () => {
it('pkpSign', () =>
createPkpSignTest(ctx, () => ctx.aliceEoaAuthContext)());
it('executeJs', () =>
createExecuteJsTest(ctx, () => ctx.aliceEoaAuthContext)());
createExecuteJsBasicTest(ctx, () => ctx.aliceEoaAuthContext)());
it('executeJs decryptAndCombine', () =>
createExecuteJsDecryptAndCombineTest(
ctx,
() => ctx.aliceEoaAuthContext
)());
it('viewPKPsByAddress', () => createViewPKPsByAddressTest(ctx)());
it('viewPKPsByAuthData', () =>
createViewPKPsByAuthDataTest(ctx, () => ctx.aliceEoaAuthContext)());
Expand Down Expand Up @@ -96,7 +99,7 @@ describe('all', () => {
it('pkpSign', () =>
createPkpSignTest(ctx, () => ctx.alicePkpAuthContext)());
it('executeJs', () =>
createExecuteJsTest(ctx, () => ctx.alicePkpAuthContext)());
createExecuteJsBasicTest(ctx, () => ctx.alicePkpAuthContext)());
it('viewPKPsByAddress', () => createViewPKPsByAddressTest(ctx)());
it('viewPKPsByAuthData', () =>
createViewPKPsByAuthDataTest(ctx, () => ctx.alicePkpAuthContext)());
Expand Down Expand Up @@ -137,7 +140,7 @@ describe('all', () => {
ctx.eveViemAccountPkp.pubkey
)());
it('executeJs', () =>
createExecuteJsTest(
createExecuteJsBasicTest(
ctx,
() => eveCustomAuthContext,
ctx.eveViemAccountPkp.pubkey
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { init } from '../../init';
import { init } from '../../../init';
import { AuthContext } from '../../../types';

export const createExecuteJsTest = (
ctx: Awaited<ReturnType<typeof init>>,
getAuthContext: () => any,
type ExecuteJsContext = Pick<
Awaited<ReturnType<typeof init>>,
'litClient' | 'aliceViemAccountPkp'
>;

export const createExecuteJsBasicTest = (
ctx: ExecuteJsContext,
getAuthContext: () => AuthContext,
pubkey?: string
) => {
return async () => {
Expand All @@ -22,14 +28,21 @@ export const createExecuteJsTest = (
});
})();`;

const defaultPubkey = ctx.aliceViemAccountPkp?.pubkey;
const targetPubkey = pubkey ?? defaultPubkey;

if (!targetPubkey) {
throw new Error('Missing PKP public key for executeJs test');
}

const result = await ctx.litClient.executeJs({
code: litActionCode,
authContext: getAuthContext(),
jsParams: {
message: 'Test message from e2e executeJs',
sigName: 'e2e-test-sig',
toSign: 'Test message from e2e executeJs',
publicKey: pubkey || ctx.aliceViemAccountPkp.pubkey,
publicKey: targetPubkey,
},
});

Expand Down
179 changes: 179 additions & 0 deletions packages/e2e/src/helper/tests/executeJs/decrypt-and-combine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import { AuthContext, LitClientInstance } from '../../../types';

type ExecuteJsContext = {
litClient: LitClientInstance;
aliceEoaAuthContext: AuthContext;
};

export const decryptAndCombineLitAction = `
(async () => {
const results = {
step1_getCurrentCid: null,
step2_generateEntropy: null,
step3_encrypt: null,
step4_decrypt: null,
step5_verify: null,
};

try {
// Step 1: Get current action IPFS CID
const currentCid = Lit.Auth.actionIpfsIdStack[0];
results.step1_getCurrentCid = {
success: true,
cid: currentCid,
};

// Step 2: Generate entropy (32 random bytes)
const entropyHex = await Lit.Actions.runOnce(
{ waitForResponse: true, name: "generateEntropy" },
async () => {
return ethers.utils.hexlify(ethers.utils.randomBytes(32));
}
);
const entropy = ethers.utils.arrayify(entropyHex);
results.step2_generateEntropy = {
success: true,
entropyPreview: entropyHex.substring(0, 20) + "...",
entropyLength: entropy.length,
};

// Step 3: Encrypt with access control locked to current IPFS CID
const accessControlConditions = [
{
contractAddress: "",
standardContractType: "",
chain: "ethereum",
method: "",
parameters: [":currentActionIpfsId"],
returnValueTest: {
comparator: "=",
value: currentCid,
},
},
];

let encryptResult = await Lit.Actions.runOnce(
{ waitForResponse: true, name: "encrypt" },
async () => {
return JSON.stringify(
await Lit.Actions.encrypt({
accessControlConditions,
to_encrypt: ethers.utils.toUtf8Bytes(entropyHex),
})
);
}
);
encryptResult = JSON.parse(encryptResult);

// Convert ciphertext to base64 for transmission
let ciphertextStr;
if (encryptResult.ciphertext instanceof Uint8Array) {
const binaryStr = Array.from(encryptResult.ciphertext)
.map((byte) => String.fromCharCode(byte))
.join("");
ciphertextStr = btoa(binaryStr);
} else {
ciphertextStr = encryptResult.ciphertext;
}

// Convert dataToEncryptHash to hex
let dataHashStr;
if (encryptResult.dataToEncryptHash instanceof Uint8Array) {
dataHashStr = ethers.utils.hexlify(encryptResult.dataToEncryptHash);
} else {
dataHashStr = encryptResult.dataToEncryptHash;
}

results.step3_encrypt = {
success: true,
ciphertextLength: ciphertextStr.length,
ciphertextPreview: ciphertextStr.substring(0, 30) + "...",
dataToEncryptHash: dataHashStr,
};

// Step 4: Decrypt using decryptAndCombine
const decryptResult = await Lit.Actions.decryptAndCombine({
accessControlConditions,
ciphertext: encryptResult.ciphertext,
dataToEncryptHash: encryptResult.dataToEncryptHash,
authSig: null,
chain: "ethereum",
});

// Convert decrypted result to hex for comparison
let decryptedHex;
if (decryptResult instanceof Uint8Array) {
decryptedHex = ethers.utils.hexlify(decryptResult);
} else if (typeof decryptResult === "string") {
decryptedHex = decryptResult;
} else {
decryptedHex = "unknown format";
}

results.step4_decrypt = {
success: true,
decryptedDataPreview: decryptedHex.substring(0, 20) + "...",
decryptedLength: decryptResult.length,
};

// Step 5: Verify original matches decrypted
const matches = entropyHex === decryptedHex;
results.step5_verify = {
success: true,
matches,
originalPreview: entropyHex.substring(0, 20) + "...",
decryptedPreview: decryptedHex.substring(0, 20) + "...",
};

Lit.Actions.setResponse({
response: JSON.stringify(
{
success: true,
currentCid,
results,
},
null,
2
),
});
} catch (error) {
Lit.Actions.setResponse({
response: JSON.stringify(
{
success: false,
error: error.message,
results,
},
null,
2
),
});
}
})();`;

export const createExecuteJsDecryptAndCombineTest = (
ctx: ExecuteJsContext,
getAuthContext: () => AuthContext = () => ctx.aliceEoaAuthContext
) => {
return async () => {
const result = await ctx.litClient.executeJs({
code: decryptAndCombineLitAction,
authContext: getAuthContext(),
jsParams: {},
});

if (typeof result.response !== 'string') {
throw new Error('Expected executeJs response to be a string payload');
}

const parsed = JSON.parse(result.response);

expect(parsed.success).toBe(true);
expect(parsed.currentCid).toBeDefined();
expect(parsed.results?.step1_getCurrentCid?.success).toBe(true);
expect(parsed.results?.step2_generateEntropy?.entropyLength).toBe(32);
expect(parsed.results?.step3_encrypt?.success).toBe(true);
expect(parsed.results?.step4_decrypt?.success).toBe(true);
expect(parsed.results?.step5_verify?.matches).toBe(true);
};
};
5 changes: 5 additions & 0 deletions packages/e2e/src/helper/tests/executeJs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { createExecuteJsBasicTest } from './basic';
export {
createExecuteJsDecryptAndCombineTest,
decryptAndCombineLitAction,
} from './decrypt-and-combine';
5 changes: 4 additions & 1 deletion packages/e2e/src/helper/tests/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Endpoint tests
export { createPkpSignTest } from './pkp-sign';
export { createExecuteJsTest } from './execute-js';
export {
createExecuteJsBasicTest,
createExecuteJsDecryptAndCombineTest,
} from './executeJs';
export { createViewPKPsByAddressTest } from './view-pkps-by-address';
export { createViewPKPsByAuthDataTest } from './view-pkps-by-auth-data';
export { createPkpEncryptDecryptTest } from './pkp-encrypt-decrypt';
Expand Down
Loading
Loading