Skip to content
Open
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
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 @@ -55,7 +53,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 @@ -95,7 +98,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 @@ -136,7 +139,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