From c53d633ba8f0dfc267e3d2db24bf66ce2e217c59 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 17 Dec 2025 08:47:33 -1000 Subject: [PATCH 01/17] chore: init decrypt within la tests --- packages/e2e/src/helper/createTestAccount.ts | 13 +- .../litActions/decryptWithinLitAction.ts | 39 +++++ .../encryptDecryptWithinLitAction.ts | 81 ++++++++++ .../paymentBenchmarks/paymentBenchmark.ts | 139 ++++++++++++++++++ .../e2e/src/tickets/payment-benchmark.spec.ts | 16 ++ 5 files changed, 286 insertions(+), 2 deletions(-) create mode 100644 packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts create mode 100644 packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts create mode 100644 packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts create mode 100644 packages/e2e/src/tickets/payment-benchmark.spec.ts diff --git a/packages/e2e/src/helper/createTestAccount.ts b/packages/e2e/src/helper/createTestAccount.ts index 55cc897b4..bed05bfa5 100644 --- a/packages/e2e/src/helper/createTestAccount.ts +++ b/packages/e2e/src/helper/createTestAccount.ts @@ -27,6 +27,11 @@ type CreateTestAccountOpts = { }; userAddresses: string[] | `0x${string}`[]; }; + /** + * Optional: Use a fixed private key instead of generating a new random one. + * This allows reusing the same test account across multiple test runs. + */ + privateKey?: `0x${string}`; }; export type CreateTestAccountResult = { @@ -49,8 +54,9 @@ export async function createTestAccount( ): Promise { console.log(`--- ${`[${opts.label}]`} Creating test account ---`); // 1. store result + const privateKey = opts.privateKey ?? generatePrivateKey(); let person: CreateTestAccountResult = { - account: privateKeyToAccount(generatePrivateKey()), + account: privateKeyToAccount(privateKey), pkp: undefined, eoaAuthContext: undefined, pkpAuthContext: undefined, @@ -66,7 +72,10 @@ export async function createTestAccount( person.authData = personAccountAuthData; console.log(`Address`, person.account.address); - console.log(`opts:`, opts); + console.log(`opts:`, { + ...opts, + privateKey: opts.privateKey ? (opts.privateKey.slice(0, 6) + '...') : undefined, + }); // 3. fund it if (opts.fundAccount) { diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts new file mode 100644 index 000000000..8dce2ec8a --- /dev/null +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts @@ -0,0 +1,39 @@ +export const DECRYPT_WITHIN_LIT_ACTION = ` +(async () => { + const { accessControlConditions, ciphertext, dataToEncryptHash } = jsParams; + + // Decrypt the API key + const decryptedApiKey = await Lit.Actions.decryptAndCombine({ + accessControlConditions, + ciphertext, + dataToEncryptHash, + authSig: null, + chain: "ethereum", + }); + + // Parse the decrypted API key + const apiKey = JSON.parse(decryptedApiKey); + + // Use the API key in a fetch request + const response = await fetch("https://api.coingecko.com/api/v3/ping", { + method: "GET", + headers: { + "Authorization": \`Bearer \${apiKey.key}\`, + "Content-Type": "application/json", + }, + }); + + const responseData = await response.json(); + + // Simulate runtime of 5 seconds + await new Promise((resolve) => setTimeout(resolve, 5000)); + + Lit.Actions.setResponse({ + response: JSON.stringify({ + success: true, + data: responseData, + // Note: We don't expose the actual API key in the response + }), + }); +})(); +`; diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts new file mode 100644 index 000000000..ddde36562 --- /dev/null +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts @@ -0,0 +1,81 @@ +export const ENCRYPT_DECRYPT_WITHIN_LIT_ACTION = ` +const go = async () => { + // First, encrypt an API key (simulating a stored encrypted API key) + // In a real scenario, this would already be encrypted and stored + const apiKeyData = JSON.stringify({ key: "example-api-key-12345" }); + const currentCid = Lit.Auth.actionIpfsIdStack[0]; + + // const accessControlConditions = [ + // { + // contractAddress: "", + // standardContractType: "", + // chain: "ethereum", + // method: "", + // parameters: [":currentActionIpfsId"], + // returnValueTest: { + // comparator: "=", + // value: currentCid, + // }, + // }, + // ]; + + const accessControlConditions = [ + { + contractAddress: "", + standardContractType: "", + chain: "ethereum", + method: "", + parameters: ["1"], + returnValueTest: { + comparator: "=", + value: "1", + }, + }, + ]; + + // Encrypt the API key + const { ciphertext, dataToEncryptHash } = await Lit.Actions.encrypt({ + accessControlConditions, + to_encrypt: ethers.utils.toUtf8Bytes(apiKeyData), + }); + + console.log('ciphertext', ciphertext); + console.log('dataToEncryptHash', dataToEncryptHash); + + // Now decrypt the API key (this is the actual decrypt operation we're counting) + const decryptedApiKey = await Lit.Actions.decryptAndCombine({ + accessControlConditions, + ciphertext, + dataToEncryptHash, + authSig: null, + chain: "ethereum", + }); + + // Parse the decrypted API key + const apiKey = JSON.parse(decryptedApiKey); + + // Use the API key in a fetch request + const response = await fetch("https://api.coingecko.com/api/v3/ping", { + method: "GET", + headers: { + "Authorization": \`Bearer \${apiKey.key}\`, + "Content-Type": "application/json", + }, + }); + + const responseData = await response.json(); + + Simulate runtime of 5 seconds + await new Promise((resolve) => setTimeout(resolve, 5000)); + + Lit.Actions.setResponse({ + response: JSON.stringify({ + success: true, + data: responseData, + // Note: We don't expose the actual API key in the response + }), + }); +}; + +go(); +`; \ No newline at end of file diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts new file mode 100644 index 000000000..b678eb0be --- /dev/null +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts @@ -0,0 +1,139 @@ +import { createEnvVars } from '../../../helper/createEnvVars'; +import { + createTestAccount, + CreateTestAccountResult, +} from '../../../helper/createTestAccount'; +import { createTestEnv } from '../../../helper/createTestEnv'; +import { DECRYPT_WITHIN_LIT_ACTION } from './litActions/decryptWithinLitAction'; +import { ENCRYPT_DECRYPT_WITHIN_LIT_ACTION } from './litActions/encryptDecryptWithinLitAction'; + +const stringifyWithBigInt = (value: unknown) => + JSON.stringify( + value, + (_key, val) => (typeof val === 'bigint' ? val.toString() : val), + 2 + ); + +export const registerPaymentBenchmarkTests = () => { + let testEnv: Awaited>; + let benchmarkUser: CreateTestAccountResult; + + beforeAll(async () => { + const envVars = createEnvVars(); + testEnv = await createTestEnv(envVars); + + // Use TEST_ALICE_PRIVATE_KEY if available to reuse the same account across test runs + const privateKey = process.env['TEST_ALICE_PRIVATE_KEY'] as `0x${string}` | undefined; + + benchmarkUser = await createTestAccount(testEnv, { + label: 'Payment Benchmark User', + privateKey, // Reuse account if env var is set + fundAccount: true, + fundLedger: true, + hasEoaAuthContext: true, + hasPKP: false, + fundPKP: false, + hasPKPAuthContext: false, + fundPKPLedger: false, + }); + + if (!benchmarkUser.eoaAuthContext) { + throw new Error( + 'EOA auth context was not created for payment benchmark test' + ); + } + }, 120000); // Increased timeout for setup + + describe('Payment Benchmark Tests', () => { + describe('Secure API Key Usage', () => { + test.skip('should encrypt outside the Lit Action, and decrypt and make a fetch request inside the Lit Action', async () => { + // Encrypt the API key outside the Lit Action (simulating a pre-encrypted stored API key) + const apiKeyData = JSON.stringify({ key: "example-api-key-12345" }); + + // Create always-true access control conditions for the benchmark + const accessControlConditions = [ + { + contractAddress: "", + standardContractType: "" as const, + chain: "ethereum" as const, + method: "", + parameters: ["1"], + returnValueTest: { + comparator: "=" as const, + value: "1", + }, + }, + ]; + + const encryptedData = await testEnv.litClient.encrypt({ + dataToEncrypt: apiKeyData, + accessControlConditions, + chain: 'ethereum', + }); + + const executionResult = await testEnv.litClient.executeJs({ + code: DECRYPT_WITHIN_LIT_ACTION, + authContext: benchmarkUser.eoaAuthContext!, + jsParams: { + accessControlConditions, + ciphertext: encryptedData.ciphertext, + dataToEncryptHash: encryptedData.dataToEncryptHash, + }, + }); + console.log('executionResult', executionResult); + + // Verify successful execution + expect(executionResult.response).toBeDefined(); + const response = JSON.parse(executionResult.response as string); + expect(response.success).toBe(true); + expect(response.data).toBeDefined(); + + // Verify payment details are returned + expect(executionResult.paymentDetail).toBeDefined(); + expect(Array.isArray(executionResult.paymentDetail)).toBe(true); + expect(executionResult.paymentDetail!.length).toBeGreaterThan(0); + + const paymentDetail = executionResult.paymentDetail!; + console.log(executionResult); + console.log('\nPayment Details:'); + console.log(stringifyWithBigInt(paymentDetail)); + + // Calculate total cost + const totalCost = paymentDetail.reduce((sum, entry) => { + return sum + entry.price; + }, 0n); + console.log(`\nTotal Cost: ${totalCost.toString()}`); + }, 120000); // 2 minute timeout for the test (includes 5s wait in action) + + test('should encrypt, decrypt and make a fetch request within the Lit Action', async () => { + const executionResult = await testEnv.litClient.executeJs({ + code: ENCRYPT_DECRYPT_WITHIN_LIT_ACTION, + authContext: benchmarkUser.eoaAuthContext!, + jsParams: {}, + }); + console.log('executionResult', executionResult); + + // Verify successful execution + expect(executionResult.response).toBeDefined(); + const response = JSON.parse(executionResult.response as string); + expect(response.success).toBe(true); + expect(response.data).toBeDefined(); + + // Verify payment details are returned + expect(executionResult.paymentDetail).toBeDefined(); + expect(Array.isArray(executionResult.paymentDetail)).toBe(true); + expect(executionResult.paymentDetail!.length).toBeGreaterThan(0); + + const paymentDetail = executionResult.paymentDetail!; + console.log('\nPayment Details:'); + console.log(stringifyWithBigInt(paymentDetail)); + + // Calculate total cost + const totalCost = paymentDetail.reduce((sum, entry) => { + return sum + entry.price; + }, 0n); + console.log(`\nTotal Cost: ${totalCost.toString()}`); + }, 120000); // 2 minute timeout for the test (includes 5s wait in action) + }); + }); +}; diff --git a/packages/e2e/src/tickets/payment-benchmark.spec.ts b/packages/e2e/src/tickets/payment-benchmark.spec.ts new file mode 100644 index 000000000..26601e27b --- /dev/null +++ b/packages/e2e/src/tickets/payment-benchmark.spec.ts @@ -0,0 +1,16 @@ +import { registerPaymentBenchmarkTests } from '../test-helpers/executeJs/paymentBenchmarks/paymentBenchmark'; + +/** + * Payment Benchmark Tests + * + * These tests benchmark the cost of executing various Lit Actions + * that perform different operations with varying execution times. + * + * Each test: + * - Executes a specific Lit Action scenario + * - Measures payment details (component costs, quantities, prices) + * - Logs detailed cost breakdown for documentation + * + * Test against: naga-test network + */ +registerPaymentBenchmarkTests(); From cc8739280652c407aac2b83fc024b882daa7137e Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 17 Dec 2025 08:48:35 -1000 Subject: [PATCH 02/17] chore: add TEST_ALICE_PRIVATE_KEY and TEST_BOB_PRIVATE_KEY to sample env --- .env.sample | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.env.sample b/.env.sample index bb3fe9375..927735f42 100644 --- a/.env.sample +++ b/.env.sample @@ -7,3 +7,6 @@ LOCAL_MASTER_ACCOUNT=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf NODE_NO_WARNINGS=1 NODE_OPTIONS=--no-deprecation + +TEST_ALICE_PRIVATE_KEY= +TEST_BOB_PRIVATE_KEY= From 5a256189f6d736aedd78c9fa5c38df1f15122925 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 17 Dec 2025 09:05:24 -1000 Subject: [PATCH 03/17] chore: add note for new envs in env.sample --- .env.sample | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.env.sample b/.env.sample index 927735f42..644361893 100644 --- a/.env.sample +++ b/.env.sample @@ -8,5 +8,12 @@ LOCAL_MASTER_ACCOUNT=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf NODE_NO_WARNINGS=1 NODE_OPTIONS=--no-deprecation +# These environment variables are optional and allow you to reuse a single test account. +# This is especially useful when testing against a paid Naga network, where the test +# account must have tokens deposited into the Ledger contract to cover request costs. +# +# By providing private key(s) here, you can avoid depositing funds for each test run. +# Without these variables, a new test account is generated on every run, requiring +# fresh funding each time. TEST_ALICE_PRIVATE_KEY= TEST_BOB_PRIVATE_KEY= From 0eb7b0a4dab09dd50be4a048d50c9ce7524e4358 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 17 Dec 2025 11:44:44 -1000 Subject: [PATCH 04/17] chore: update test for debugging --- .../encryptDecryptWithinLitAction.ts | 132 ++++++++---------- 1 file changed, 62 insertions(+), 70 deletions(-) diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts index ddde36562..327e4cd0a 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts @@ -1,81 +1,73 @@ -export const ENCRYPT_DECRYPT_WITHIN_LIT_ACTION = ` -const go = async () => { - // First, encrypt an API key (simulating a stored encrypted API key) - // In a real scenario, this would already be encrypted and stored - const apiKeyData = JSON.stringify({ key: "example-api-key-12345" }); - const currentCid = Lit.Auth.actionIpfsIdStack[0]; +declare const Lit: any; +declare const ethers: any; - // const accessControlConditions = [ - // { - // contractAddress: "", - // standardContractType: "", - // chain: "ethereum", - // method: "", - // parameters: [":currentActionIpfsId"], - // returnValueTest: { - // comparator: "=", - // value: currentCid, - // }, - // }, - // ]; +async function encryptDecryptWithinLitAction() { + // First, encrypt an API key (simulating a stored encrypted API key) + // In a real scenario, this would already be encrypted and stored + const apiKeyData = JSON.stringify({ key: "example-api-key-12345" }); - const accessControlConditions = [ - { - contractAddress: "", - standardContractType: "", - chain: "ethereum", - method: "", - parameters: ["1"], - returnValueTest: { - comparator: "=", - value: "1", - }, - }, - ]; + const accessControlConditions = [ + { + contractAddress: "", + standardContractType: "", + chain: "ethereum", + method: "", + parameters: ["1"], + returnValueTest: { + comparator: "=", + value: "1", + }, + }, + ]; - // Encrypt the API key - const { ciphertext, dataToEncryptHash } = await Lit.Actions.encrypt({ - accessControlConditions, - to_encrypt: ethers.utils.toUtf8Bytes(apiKeyData), - }); + // Encrypt the API key + const { ciphertext, dataToEncryptHash } = await Lit.Actions.encrypt({ + accessControlConditions, + to_encrypt: ethers.utils.toUtf8Bytes(apiKeyData), + }); - console.log('ciphertext', ciphertext); - console.log('dataToEncryptHash', dataToEncryptHash); + console.log('ciphertext', ciphertext); + console.log('dataToEncryptHash', dataToEncryptHash); - // Now decrypt the API key (this is the actual decrypt operation we're counting) - const decryptedApiKey = await Lit.Actions.decryptAndCombine({ - accessControlConditions, - ciphertext, - dataToEncryptHash, - authSig: null, - chain: "ethereum", - }); + // Now decrypt the API key (this is the actual decrypt operation we're counting) + const decryptedApiKey = await Lit.Actions.decryptAndCombine({ + accessControlConditions, + ciphertext: 'iRWRrnG57m8iN/o1phlEV1PToXgDEAVbhHhZuxxH9k0UCx09L3VTYojGkB7AC1XM8D340+Fy5pIKQ3ypQTpMFBaKR27IlXr2oOsPuKxQwTggA5FmHE8lYfviT0/VuT0TUUJLIVc7fKMZoqK1UKj+I+kC', + dataToEncryptHash: '3a7a6315ce5f1c0a619a44b27450feacf20d75beb598f505c890c1f0cfd23d74', + // ciphertext, + // dataToEncryptHash, + authSig: null, + chain: "ethereum", + }); - // Parse the decrypted API key - const apiKey = JSON.parse(decryptedApiKey); + console.log('decryptedApiKey', decryptedApiKey); - // Use the API key in a fetch request - const response = await fetch("https://api.coingecko.com/api/v3/ping", { - method: "GET", - headers: { - "Authorization": \`Bearer \${apiKey.key}\`, - "Content-Type": "application/json", - }, - }); + // // Parse the decrypted API key + // const apiKey = JSON.parse(decryptedApiKey); - const responseData = await response.json(); + // // Use the API key in a fetch request + // const response = await fetch("https://api.coingecko.com/api/v3/ping", { + // method: "GET", + // headers: { + // "Authorization": `Bearer ${apiKey.key}`, + // "Content-Type": "application/json", + // }, + // }); - Simulate runtime of 5 seconds - await new Promise((resolve) => setTimeout(resolve, 5000)); + // const responseData = await response.json(); - Lit.Actions.setResponse({ - response: JSON.stringify({ - success: true, - data: responseData, - // Note: We don't expose the actual API key in the response - }), - }); -}; + // // Simulate runtime of 5 seconds + // await new Promise((resolve) => setTimeout(resolve, 5000)); -go(); -`; \ No newline at end of file + Lit.Actions.setResponse({ + response: JSON.stringify({ + success: true, + // data: responseData, + data: 'payment benchmark success', + // Note: We don't expose the actual API key in the response + }), + }); +} + +// Convert the function to a string and wrap it in an IIFE +export const ENCRYPT_DECRYPT_WITHIN_LIT_ACTION = `(${encryptDecryptWithinLitAction.toString()})();`; \ No newline at end of file From b187423c4e87e7a3ca422570d06fcac72543d69b Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 17 Dec 2025 13:47:45 -1000 Subject: [PATCH 05/17] fix: encrypt within la test --- .../encryptDecryptWithinLitAction.ts | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts index 327e4cd0a..289c7cfad 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts @@ -5,6 +5,7 @@ async function encryptDecryptWithinLitAction() { // First, encrypt an API key (simulating a stored encrypted API key) // In a real scenario, this would already be encrypted and stored const apiKeyData = JSON.stringify({ key: "example-api-key-12345" }); + const currentCid = Lit.Auth.actionIpfsIdStack[0]; const accessControlConditions = [ { @@ -12,58 +13,57 @@ async function encryptDecryptWithinLitAction() { standardContractType: "", chain: "ethereum", method: "", - parameters: ["1"], + parameters: [":currentActionIpfsId"], returnValueTest: { comparator: "=", - value: "1", + value: currentCid, }, }, ]; - // Encrypt the API key - const { ciphertext, dataToEncryptHash } = await Lit.Actions.encrypt({ - accessControlConditions, - to_encrypt: ethers.utils.toUtf8Bytes(apiKeyData), - }); - - console.log('ciphertext', ciphertext); - console.log('dataToEncryptHash', dataToEncryptHash); + // Encrypt the API key (using runOnce to ensure it only runs on one node) + const encryptResult = await Lit.Actions.runOnce( + { waitForResponse: true, name: "encryptApiKey" }, + async () => { + const result = await Lit.Actions.encrypt({ + accessControlConditions, + to_encrypt: ethers.utils.toUtf8Bytes(apiKeyData), + }); + return JSON.stringify(result); + } + ); + const { ciphertext, dataToEncryptHash } = JSON.parse(encryptResult); // Now decrypt the API key (this is the actual decrypt operation we're counting) const decryptedApiKey = await Lit.Actions.decryptAndCombine({ accessControlConditions, - ciphertext: 'iRWRrnG57m8iN/o1phlEV1PToXgDEAVbhHhZuxxH9k0UCx09L3VTYojGkB7AC1XM8D340+Fy5pIKQ3ypQTpMFBaKR27IlXr2oOsPuKxQwTggA5FmHE8lYfviT0/VuT0TUUJLIVc7fKMZoqK1UKj+I+kC', - dataToEncryptHash: '3a7a6315ce5f1c0a619a44b27450feacf20d75beb598f505c890c1f0cfd23d74', - // ciphertext, - // dataToEncryptHash, + ciphertext, + dataToEncryptHash, authSig: null, chain: "ethereum", }); - console.log('decryptedApiKey', decryptedApiKey); + // Parse the decrypted API key + const apiKey = JSON.parse(decryptedApiKey); - // // Parse the decrypted API key - // const apiKey = JSON.parse(decryptedApiKey); - - // // Use the API key in a fetch request - // const response = await fetch("https://api.coingecko.com/api/v3/ping", { - // method: "GET", - // headers: { - // "Authorization": `Bearer ${apiKey.key}`, - // "Content-Type": "application/json", - // }, - // }); + // Use the API key in a fetch request + const response = await fetch("https://api.coingecko.com/api/v3/ping", { + method: "GET", + headers: { + "Authorization": `Bearer ${apiKey.key}`, + "Content-Type": "application/json", + }, + }); - // const responseData = await response.json(); + const responseData = await response.json(); - // // Simulate runtime of 5 seconds - // await new Promise((resolve) => setTimeout(resolve, 5000)); + // Simulate runtime of 5 seconds + await new Promise((resolve) => setTimeout(resolve, 5000)); Lit.Actions.setResponse({ response: JSON.stringify({ success: true, - // data: responseData, - data: 'payment benchmark success', + data: responseData, // Note: We don't expose the actual API key in the response }), }); From 16ba5b112e86a17db52de8bc0c1a5535fd2c1b4a Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 17 Dec 2025 21:21:26 -1000 Subject: [PATCH 06/17] chore: add verifiable data test --- .../litActions/decryptWithinLitAction.ts | 19 ++++-- .../encryptDecryptWithinLitAction.ts | 6 ++ .../litActions/verifiableDataJob.ts | 66 +++++++++++++++++++ .../paymentBenchmarks/paymentBenchmark.ts | 60 +++++++++++++---- 4 files changed, 135 insertions(+), 16 deletions(-) create mode 100644 packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/verifiableDataJob.ts diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts index 8dce2ec8a..6a733118f 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts @@ -1,5 +1,13 @@ -export const DECRYPT_WITHIN_LIT_ACTION = ` -(async () => { +declare const Lit: any; +declare const jsParams: any; + +/** + * Lit Action: Decrypt within the Lit Action + * + * Decrypts an API key and makes a fetch request within the Lit Action. + * Runtime: ~5 seconds, Fetches: 1, Decrypts: 1 + */ +async function decryptWithinLitAction() { const { accessControlConditions, ciphertext, dataToEncryptHash } = jsParams; // Decrypt the API key @@ -18,7 +26,7 @@ export const DECRYPT_WITHIN_LIT_ACTION = ` const response = await fetch("https://api.coingecko.com/api/v3/ping", { method: "GET", headers: { - "Authorization": \`Bearer \${apiKey.key}\`, + "Authorization": `Bearer ${apiKey.key}`, "Content-Type": "application/json", }, }); @@ -35,5 +43,6 @@ export const DECRYPT_WITHIN_LIT_ACTION = ` // Note: We don't expose the actual API key in the response }), }); -})(); -`; +} + +export const DECRYPT_WITHIN_LIT_ACTION = `(${decryptWithinLitAction.toString()})();`; diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts index 289c7cfad..e0e7dd0ab 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts @@ -1,6 +1,12 @@ declare const Lit: any; declare const ethers: any; +/** + * Lit Action: Encrypt and Decrypt within the Lit Action + * + * Encrypts an API key and decrypts it within the Lit Action. + * Runtime: ~5 seconds, Fetches: 1, Encrypts: 1, Decrypts: 1 + */ async function encryptDecryptWithinLitAction() { // First, encrypt an API key (simulating a stored encrypted API key) // In a real scenario, this would already be encrypted and stored diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/verifiableDataJob.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/verifiableDataJob.ts new file mode 100644 index 000000000..3c3bf7104 --- /dev/null +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/verifiableDataJob.ts @@ -0,0 +1,66 @@ +declare const Lit: any; +declare const ethers: any; +declare const jsParams: any; + +/** + * Lit Action: Verifiable Data Job + * + * Processes data locally and signs the result to create a verifiable attestation. + * Runtime: ~45 seconds, Fetches: 0, Signatures: 1, Decrypts: 0 + */ +async function verifiableDataJob() { + // Generate and process data locally (using runOnce to ensure it only runs on one node) + const dataResult = await Lit.Actions.runOnce( + { waitForResponse: true, name: "generateData" }, + async () => { + const dataPoints = []; + for (let i = 0; i < 1000; i++) { + const randomValue = Math.random() * 1000; + const processedValue = Math.sqrt(randomValue) * Math.PI; + dataPoints.push({ + index: i, + value: processedValue, + hash: ethers.utils.keccak256(ethers.utils.toUtf8Bytes(processedValue.toString())), + }); + } + + // Aggregate the processed data + const aggregatedData = { + totalPoints: dataPoints.length, + averageValue: dataPoints.reduce((sum, p) => sum + p.value, 0) / dataPoints.length, + dataHash: ethers.utils.keccak256( + ethers.utils.toUtf8Bytes(dataPoints.map(p => p.hash).join("")) + ), + timestamp: Date.now(), + }; + + return JSON.stringify(aggregatedData); + } + ); + + const aggregatedData = JSON.parse(dataResult); + console.log('aggregatedData', aggregatedData); + + // Simulate processing time + await new Promise((resolve) => setTimeout(resolve, 45000)); + + // Sign the processed result + const toSign = ethers.utils.arrayify( + ethers.utils.keccak256(ethers.utils.toUtf8Bytes(JSON.stringify(aggregatedData))) + ); + await Lit.Actions.signEcdsa({ + toSign, + publicKey: jsParams.pkpPublicKey, + sigName: "verifiable-data-signature", + }); + + Lit.Actions.setResponse({ + response: JSON.stringify({ + aggregatedData, + data: 'payment benchmark success', + }), + }); +} + +// Convert the function to a string and wrap it in an IIFE +export const VERIFIABLE_DATA_JOB_LIT_ACTION = `(${verifiableDataJob.toString()})();`; diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts index b678eb0be..fe03e7e0e 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts @@ -6,6 +6,7 @@ import { import { createTestEnv } from '../../../helper/createTestEnv'; import { DECRYPT_WITHIN_LIT_ACTION } from './litActions/decryptWithinLitAction'; import { ENCRYPT_DECRYPT_WITHIN_LIT_ACTION } from './litActions/encryptDecryptWithinLitAction'; +import { VERIFIABLE_DATA_JOB_LIT_ACTION } from './litActions/verifiableDataJob'; const stringifyWithBigInt = (value: unknown) => JSON.stringify( @@ -31,22 +32,16 @@ export const registerPaymentBenchmarkTests = () => { fundAccount: true, fundLedger: true, hasEoaAuthContext: true, - hasPKP: false, + hasPKP: true, fundPKP: false, hasPKPAuthContext: false, fundPKPLedger: false, }); - - if (!benchmarkUser.eoaAuthContext) { - throw new Error( - 'EOA auth context was not created for payment benchmark test' - ); - } }, 120000); // Increased timeout for setup describe('Payment Benchmark Tests', () => { - describe('Secure API Key Usage', () => { - test.skip('should encrypt outside the Lit Action, and decrypt and make a fetch request inside the Lit Action', async () => { + describe.skip('Secure API Key Usage', () => { + test('should encrypt outside the Lit Action, and decrypt and make a fetch request inside the Lit Action', async () => { // Encrypt the API key outside the Lit Action (simulating a pre-encrypted stored API key) const apiKeyData = JSON.stringify({ key: "example-api-key-12345" }); @@ -103,7 +98,7 @@ export const registerPaymentBenchmarkTests = () => { return sum + entry.price; }, 0n); console.log(`\nTotal Cost: ${totalCost.toString()}`); - }, 120000); // 2 minute timeout for the test (includes 5s wait in action) + }, 120000); // 2 minute timeout test('should encrypt, decrypt and make a fetch request within the Lit Action', async () => { const executionResult = await testEnv.litClient.executeJs({ @@ -133,7 +128,50 @@ export const registerPaymentBenchmarkTests = () => { return sum + entry.price; }, 0n); console.log(`\nTotal Cost: ${totalCost.toString()}`); - }, 120000); // 2 minute timeout for the test (includes 5s wait in action) + }, 120000); // 2 minute timeout + }); + + describe('Verifiable Data Job', () => { + test('should process data and sign the result', async () => { + console.log('benchmarkUser', benchmarkUser); + + const executionResult = await testEnv.litClient.executeJs({ + code: VERIFIABLE_DATA_JOB_LIT_ACTION, + authContext: benchmarkUser.eoaAuthContext!, + jsParams: { + pkpPublicKey: benchmarkUser.pkp!.pubkey, + }, + }); + + console.log('executionResult', executionResult); + + // Verify successful execution + expect(executionResult.response).toBeDefined(); + const { response } = executionResult as any; + expect(response.aggregatedData).toBeDefined(); + expect(response.aggregatedData.totalPoints).toBe(1000); + expect(response.aggregatedData.averageValue).toBeGreaterThan(0); + expect(response.aggregatedData.dataHash).toBeDefined(); + expect(response.aggregatedData.timestamp).toBeGreaterThan(0); + + expect(executionResult.signatures).toBeDefined(); + expect(executionResult.signatures['verifiable-data-signature']).toBeDefined(); + + // Verify payment details are returned + expect(executionResult.paymentDetail).toBeDefined(); + expect(Array.isArray(executionResult.paymentDetail)).toBe(true); + expect(executionResult.paymentDetail!.length).toBeGreaterThan(0); + + const paymentDetail = executionResult.paymentDetail!; + console.log('\nPayment Details:'); + console.log(stringifyWithBigInt(paymentDetail)); + + // Calculate total cost + const totalCost = paymentDetail.reduce((sum, entry) => { + return sum + entry.price; + }, 0n); + console.log(`\nTotal Cost: ${totalCost.toString()}`); + }, 120000); // 2 minute timeout }); }); }; From 47ce1958192651098f60f4008a9644dfcacd527c Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 17 Dec 2025 21:28:13 -1000 Subject: [PATCH 07/17] chore: init oracle test --- .../litActions/oracleOperation.ts | 59 +++++++++++++++++++ .../paymentBenchmarks/paymentBenchmark.ts | 41 ++++++++++++- 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts new file mode 100644 index 000000000..a3a0becf1 --- /dev/null +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts @@ -0,0 +1,59 @@ +declare const Lit: any; +declare const ethers: any; + +/** + * Lit Action: Oracle Operation + * + * Fetches external data and signs the result using broadcastAndCollect to medianize prices. + * Runtime: ~10 seconds, Fetches: 1, Signatures: 1, Decrypts: 0 + */ +async function oracleOperation() { + // Helper function to calculate median + const median = (arr: number[]) => { + const arrSorted = arr.sort((a, b) => a - b); + return arrSorted.length % 2 === 0 + ? (arrSorted[arrSorted.length / 2 - 1] + arrSorted[arrSorted.length / 2]) / 2 + : arrSorted[Math.floor(arrSorted.length / 2)]; + }; + + // Fetch external data (e.g., price oracle data) + const response = await fetch( + "https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd" + ); + const data = await response.json(); + + // Collect prices from all the nodes + const allPrices = await Lit.Actions.broadcastAndCollect({ + name: "ethPrice", + value: data.ethereum.usd.toString(), + }); + + // Medianize the price, so that outliers don't skew the result + const medianPrice = median(allPrices); + + // Process the fetched data + const priceHash = ethers.utils.hashMessage( + ethers.utils.toUtf8Bytes(medianPrice.toString()) + ); + + // Sign the result + const toSign = ethers.utils.arrayify(priceHash); + await Lit.Actions.signAsAction({ + toSign, + signingScheme: "EcdsaK256Sha256", + sigName: "oracle-signature", + }); + + // Simulate runtime of 10 seconds + await new Promise((resolve) => setTimeout(resolve, 10000)); + + Lit.Actions.setResponse({ + response: JSON.stringify({ + medianPrice, + data: 'payment benchmark success', + }), + }); +} + +// Convert the function to a string and wrap it in an IIFE +export const ORACLE_OPERATION_LIT_ACTION = `(${oracleOperation.toString()})();`; diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts index fe03e7e0e..e2290ab83 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts @@ -7,6 +7,7 @@ import { createTestEnv } from '../../../helper/createTestEnv'; import { DECRYPT_WITHIN_LIT_ACTION } from './litActions/decryptWithinLitAction'; import { ENCRYPT_DECRYPT_WITHIN_LIT_ACTION } from './litActions/encryptDecryptWithinLitAction'; import { VERIFIABLE_DATA_JOB_LIT_ACTION } from './litActions/verifiableDataJob'; +import { ORACLE_OPERATION_LIT_ACTION } from './litActions/oracleOperation'; const stringifyWithBigInt = (value: unknown) => JSON.stringify( @@ -131,7 +132,7 @@ export const registerPaymentBenchmarkTests = () => { }, 120000); // 2 minute timeout }); - describe('Verifiable Data Job', () => { + describe.skip('Verifiable Data Job', () => { test('should process data and sign the result', async () => { console.log('benchmarkUser', benchmarkUser); @@ -173,5 +174,43 @@ export const registerPaymentBenchmarkTests = () => { console.log(`\nTotal Cost: ${totalCost.toString()}`); }, 120000); // 2 minute timeout }); + + describe('Oracle Operation', () => { + test('should fetch external data, medianize prices, and sign the result', async () => { + const executionResult = await testEnv.litClient.executeJs({ + code: ORACLE_OPERATION_LIT_ACTION, + authContext: benchmarkUser.eoaAuthContext!, + jsParams: {}, + }); + + console.log('executionResult', executionResult); + + // Verify successful execution + expect(executionResult.response).toBeDefined(); + const { response } = executionResult as any; + expect(response.medianPrice).toBeDefined(); + expect(parseFloat(response.medianPrice)).toBeGreaterThan(0); + expect(response.data).toBe('payment benchmark success'); + + // Verify signature was created + expect(executionResult.signatures).toBeDefined(); + expect(executionResult.signatures['oracle-signature']).toBeDefined(); + + // Verify payment details are returned + expect(executionResult.paymentDetail).toBeDefined(); + expect(Array.isArray(executionResult.paymentDetail)).toBe(true); + expect(executionResult.paymentDetail!.length).toBeGreaterThan(0); + + const paymentDetail = executionResult.paymentDetail!; + console.log('\nPayment Details:'); + console.log(stringifyWithBigInt(paymentDetail)); + + // Calculate total cost + const totalCost = paymentDetail.reduce((sum, entry) => { + return sum + entry.price; + }, 0n); + console.log(`\nTotal Cost: ${totalCost.toString()}`); + }, 120000); // 2 minute timeout + }); }); }; From 40d1caeb46b97618b9fb13a80a232fbe5a4ddefb Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 17 Dec 2025 22:25:00 -1000 Subject: [PATCH 08/17] chore: wip cross chain swap test --- .../litActions/crossChainSwap.ts | 143 ++++++++++++++++++ .../paymentBenchmarks/paymentBenchmark.ts | 70 ++++++++- 2 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts new file mode 100644 index 000000000..bfc7b356f --- /dev/null +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts @@ -0,0 +1,143 @@ +declare const Lit: any; +declare const ethers: any; +declare const jsParams: any; + +/** + * Lit Action: Cross-Chain Swap + * + * Simulates a realistic cross-chain swap flow with price discovery, + * liquidity checks, slippage calculation, and multi-step signing. + * Runtime: ~20 seconds, Fetches: 4, Signatures: 2, Decrypts: 0 + */ +async function crossChainSwap() { + // Swap parameters (in a real scenario, these would come from jsParams) + const swapParams = { + sourceChain: "ethereum", + destChain: "bitcoin", + sourceToken: "ETH", + destToken: "BTC", + amountIn: "1.0", // 1 ETH + userAddress: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", // Example address + slippageTolerance: 0.5, // 0.5% + }; + + // Fetch prices and chain status (using runOnce to ensure consistent data across all nodes) + const priceDataResult = await Lit.Actions.runOnce( + { waitForResponse: true, name: "fetchPriceData" }, + async () => { + // Fetch 1: Get source token price (ETH) + const ethPriceResponse = await fetch( + "https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd" + ); + const ethPriceData = await ethPriceResponse.json(); + const ethPrice = ethPriceData.ethereum.usd; + + // Fetch 2: Get destination token price (BTC) + const bitcoinPriceResponse = await fetch( + "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd" + ); + const bitcoinPriceData = await bitcoinPriceResponse.json(); + const bitcoinPrice = bitcoinPriceData["bitcoin"].usd; + + // Fetch 3: Check source chain status (simulated via CoinGecko API health) + const sourceChainStatusResponse = await fetch("https://api.coingecko.com/api/v3/ping"); + const sourceChainStatusData = await sourceChainStatusResponse.json(); + const sourceChainStatus = sourceChainStatusData["gecko_says"]; + + // Fetch 4: Check destination chain status (simulated via CoinGecko API health) + const destChainStatusResponse = await fetch("https://api.coingecko.com/api/v3/ping"); + const destChainStatusData = await destChainStatusResponse.json(); + const destChainStatus = destChainStatusData["gecko_says"]; + + return JSON.stringify({ + ethPrice, + bitcoinPrice, + sourceChainStatus, + destChainStatus, + }); + } + ); + + const { ethPrice, bitcoinPrice, sourceChainStatus, destChainStatus } = JSON.parse(priceDataResult); + + // Calculate swap amounts based on real prices + const amountInUsd = parseFloat(swapParams.amountIn) * ethPrice; + const expectedAmountOut = amountInUsd / bitcoinPrice; + + // Simulate bridge fees and slippage + const bridgeFeePercent = 0.3; // 0.3% bridge fee + const actualSlippage = 0.2; // 0.2% actual slippage (within tolerance) + const feesAndSlippage = (bridgeFeePercent + actualSlippage) / 100; + const amountOutAfterFees = expectedAmountOut * (1 - feesAndSlippage); + const minAmountOut = expectedAmountOut * (1 - swapParams.slippageTolerance / 100); + + // Prepare swap intent data + const swapIntent = { + params: swapParams, + pricing: { + ethPrice, + bitcoinPrice, + amountInUsd, + expectedAmountOut, + minAmountOut, + amountOutAfterFees, + bridgeFeePercent, + actualSlippage, + }, + chainStatus: { + source: sourceChainStatus, + destination: destChainStatus, + }, + timestamp: Date.now(), + nonce: 123456789, + }; + + // Sign 1: Sign the swap intent (like approving the swap on source chain) + const swapIntentHash = ethers.utils.keccak256( + ethers.utils.toUtf8Bytes(JSON.stringify(swapIntent)) + ); + await Lit.Actions.signEcdsa({ + toSign: ethers.utils.arrayify(swapIntentHash), + publicKey: jsParams.pkpPublicKey, + sigName: "swap-approval-signature", + }); + + // Simulate cross-chain bridge processing time (waiting for confirmations, relayers, etc.) + await new Promise((resolve) => setTimeout(resolve, 15000)); + + // Prepare execution proof (simulates proof that swap was executed on dest chain) + const executionProof = { + swapIntentHash: swapIntentHash, + executedAmountOut: amountOutAfterFees.toString(), + sourceTxHash: ethers.utils.keccak256(ethers.utils.toUtf8Bytes(`source-${swapIntent.nonce}`)), + destTxHash: ethers.utils.keccak256(ethers.utils.toUtf8Bytes(`dest-${swapIntent.nonce}`)), + sourceBlockNumber: 18500000, + destBlockNumber: 50000000, + status: "completed", + executedAt: Date.now(), + }; + + // Sign 2: Sign the execution proof (like attesting the swap completed on dest chain) + const executionProofHash = ethers.utils.keccak256( + ethers.utils.toUtf8Bytes(JSON.stringify(executionProof)) + ); + await Lit.Actions.signEcdsa({ + toSign: ethers.utils.arrayify(executionProofHash), + publicKey: jsParams.pkpPublicKey, + sigName: "swap-execution-signature", + }); + + // Simulate remaining runtime to reach 20 seconds total + await new Promise((resolve) => setTimeout(resolve, 5000)); + + Lit.Actions.setResponse({ + response: JSON.stringify({ + swapIntent, + executionProof, + data: 'payment benchmark success', + }), + }); +} + +// Convert the function to a string and wrap it in an IIFE +export const CROSS_CHAIN_SWAP_LIT_ACTION = `(${crossChainSwap.toString()})();`; diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts index e2290ab83..f3bff0801 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts @@ -8,6 +8,7 @@ import { DECRYPT_WITHIN_LIT_ACTION } from './litActions/decryptWithinLitAction'; import { ENCRYPT_DECRYPT_WITHIN_LIT_ACTION } from './litActions/encryptDecryptWithinLitAction'; import { VERIFIABLE_DATA_JOB_LIT_ACTION } from './litActions/verifiableDataJob'; import { ORACLE_OPERATION_LIT_ACTION } from './litActions/oracleOperation'; +import { CROSS_CHAIN_SWAP_LIT_ACTION } from './litActions/crossChainSwap'; const stringifyWithBigInt = (value: unknown) => JSON.stringify( @@ -36,7 +37,7 @@ export const registerPaymentBenchmarkTests = () => { hasPKP: true, fundPKP: false, hasPKPAuthContext: false, - fundPKPLedger: false, + fundPKPLedger: true, }); }, 120000); // Increased timeout for setup @@ -175,7 +176,7 @@ export const registerPaymentBenchmarkTests = () => { }, 120000); // 2 minute timeout }); - describe('Oracle Operation', () => { + describe.skip('Oracle Operation', () => { test('should fetch external data, medianize prices, and sign the result', async () => { const executionResult = await testEnv.litClient.executeJs({ code: ORACLE_OPERATION_LIT_ACTION, @@ -212,5 +213,70 @@ export const registerPaymentBenchmarkTests = () => { console.log(`\nTotal Cost: ${totalCost.toString()}`); }, 120000); // 2 minute timeout }); + + describe('Cross-Chain Swap', () => { + test('should perform realistic cross-chain swap with price discovery and multi-step signing', async () => { + const executionResult = await testEnv.litClient.executeJs({ + code: CROSS_CHAIN_SWAP_LIT_ACTION, + authContext: benchmarkUser.eoaAuthContext!, + jsParams: { + pkpPublicKey: benchmarkUser.pkp!.pubkey, + }, + }); + + console.log('executionResult', executionResult); + + // Verify successful execution + expect(executionResult.response).toBeDefined(); + const { response } = executionResult as any; + + // Verify swap intent structure + expect(response.swapIntent).toBeDefined(); + expect(response.swapIntent.params).toBeDefined(); + expect(response.swapIntent.params.sourceChain).toBe('ethereum'); + expect(response.swapIntent.params.destChain).toBe('bitcoin'); + expect(response.swapIntent.params.amountIn).toBe('1.0'); + + // Verify pricing calculations + expect(response.swapIntent.pricing).toBeDefined(); + expect(response.swapIntent.pricing.ethPrice).toBeGreaterThan(0); + expect(response.swapIntent.pricing.bitcoinPrice).toBeGreaterThan(0); + expect(response.swapIntent.pricing.expectedAmountOut).toBeGreaterThan(0); + expect(response.swapIntent.pricing.amountOutAfterFees).toBeGreaterThan(0); + expect(response.swapIntent.pricing.amountOutAfterFees).toBeLessThan( + response.swapIntent.pricing.expectedAmountOut + ); // Fees should reduce output + + // Verify execution proof + expect(response.executionProof).toBeDefined(); + expect(response.executionProof.status).toBe('completed'); + expect(response.executionProof.sourceTxHash).toBeDefined(); + expect(response.executionProof.destTxHash).toBeDefined(); + expect(response.executionProof.sourceBlockNumber).toBeGreaterThan(0); + expect(response.executionProof.destBlockNumber).toBeGreaterThan(0); + + expect(response.data).toBe('payment benchmark success'); + + // Verify both signatures were created (approval + execution) + expect(executionResult.signatures).toBeDefined(); + expect(executionResult.signatures['swap-approval-signature']).toBeDefined(); + expect(executionResult.signatures['swap-execution-signature']).toBeDefined(); + + // Verify payment details are returned + expect(executionResult.paymentDetail).toBeDefined(); + expect(Array.isArray(executionResult.paymentDetail)).toBe(true); + expect(executionResult.paymentDetail!.length).toBeGreaterThan(0); + + const paymentDetail = executionResult.paymentDetail!; + console.log('\nPayment Details:'); + console.log(stringifyWithBigInt(paymentDetail)); + + // Calculate total cost + const totalCost = paymentDetail.reduce((sum, entry) => { + return sum + entry.price; + }, 0n); + console.log(`\nTotal Cost: ${totalCost.toString()}`); + }, 120000); // 2 minute timeout + }); }); }; From ea402b32ea455f49cee411d839187036c4a59f50 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 18 Dec 2025 15:04:40 -1000 Subject: [PATCH 09/17] chore: payment details tests with summary --- packages/e2e/src/helper/createTestAccount.ts | 40 +++--- .../litActions/crossChainSwap.ts | 83 ++++++++----- .../litActions/decryptWithinLitAction.ts | 7 +- .../encryptDecryptWithinLitAction.ts | 7 +- .../litActions/oracleOperation.ts | 7 +- .../litActions/verifiableDataJob.ts | 11 +- .../paymentBenchmarks/paymentBenchmark.ts | 116 ++++++++++++++++-- 7 files changed, 190 insertions(+), 81 deletions(-) diff --git a/packages/e2e/src/helper/createTestAccount.ts b/packages/e2e/src/helper/createTestAccount.ts index bed05bfa5..92bfe298a 100644 --- a/packages/e2e/src/helper/createTestAccount.ts +++ b/packages/e2e/src/helper/createTestAccount.ts @@ -89,27 +89,27 @@ export async function createTestAccount( thenFund: testEnv.config.nativeFundingAmount, } ); + } - // -- create EOA auth context - if (opts.hasEoaAuthContext) { - person.eoaAuthContext = await testEnv.authManager.createEoaAuthContext({ - config: { - account: person.account, - }, - authConfig: { - statement: 'I authorize the Lit Protocol to execute this Lit Action.', - domain: 'example.com', - resources: [ - ['lit-action-execution', '*'], - ['pkp-signing', '*'], - ['access-control-condition-decryption', '*'], - ], - expiration: new Date(Date.now() + 1000 * 60 * 15).toISOString(), - }, - litClient: testEnv.litClient, - }); - } - } // ... end if fundAccount + // -- create EOA auth context + if (opts.hasEoaAuthContext) { + person.eoaAuthContext = await testEnv.authManager.createEoaAuthContext({ + config: { + account: person.account, + }, + authConfig: { + statement: 'I authorize the Lit Protocol to execute this Lit Action.', + domain: 'example.com', + resources: [ + ['lit-action-execution', '*'], + ['pkp-signing', '*'], + ['access-control-condition-decryption', '*'], + ], + expiration: new Date(Date.now() + 1000 * 60 * 15).toISOString(), + }, + litClient: testEnv.litClient, + }); + } // 4. also fund the ledger if (opts.fundLedger) { diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts index bfc7b356f..957ebc514 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts @@ -7,7 +7,6 @@ declare const jsParams: any; * * Simulates a realistic cross-chain swap flow with price discovery, * liquidity checks, slippage calculation, and multi-step signing. - * Runtime: ~20 seconds, Fetches: 4, Signatures: 2, Decrypts: 0 */ async function crossChainSwap() { // Swap parameters (in a real scenario, these would come from jsParams) @@ -25,40 +24,56 @@ async function crossChainSwap() { const priceDataResult = await Lit.Actions.runOnce( { waitForResponse: true, name: "fetchPriceData" }, async () => { - // Fetch 1: Get source token price (ETH) - const ethPriceResponse = await fetch( - "https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd" - ); - const ethPriceData = await ethPriceResponse.json(); - const ethPrice = ethPriceData.ethereum.usd; - - // Fetch 2: Get destination token price (BTC) - const bitcoinPriceResponse = await fetch( - "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd" - ); - const bitcoinPriceData = await bitcoinPriceResponse.json(); - const bitcoinPrice = bitcoinPriceData["bitcoin"].usd; - - // Fetch 3: Check source chain status (simulated via CoinGecko API health) - const sourceChainStatusResponse = await fetch("https://api.coingecko.com/api/v3/ping"); - const sourceChainStatusData = await sourceChainStatusResponse.json(); - const sourceChainStatus = sourceChainStatusData["gecko_says"]; - - // Fetch 4: Check destination chain status (simulated via CoinGecko API health) - const destChainStatusResponse = await fetch("https://api.coingecko.com/api/v3/ping"); - const destChainStatusData = await destChainStatusResponse.json(); - const destChainStatus = destChainStatusData["gecko_says"]; - - return JSON.stringify({ - ethPrice, - bitcoinPrice, - sourceChainStatus, - destChainStatus, - }); + try { + // Fetch 1: Get source token price (ETH) from Coinbase + const ethPriceResponse = await fetch( + "https://api.coinbase.com/v2/prices/ETH-USD/buy" + ); + const ethPriceData = await ethPriceResponse.json(); + console.log('ethPriceData', ethPriceData); + const ethPrice = parseFloat(ethPriceData.data.amount); + + // Fetch 2: Get destination token price (BTC) from Coinbase + const bitcoinPriceResponse = await fetch( + "https://api.coinbase.com/v2/prices/BTC-USD/buy" + ); + const bitcoinPriceData = await bitcoinPriceResponse.json(); + console.log('bitcoinPriceData', bitcoinPriceData); + const bitcoinPrice = parseFloat(bitcoinPriceData.data.amount); + + // Fetch 3: Check source chain status (simulated via Coinbase system status) + const sourceChainStatusResponse = await fetch("https://api.coinbase.com/v2/time"); + const sourceChainStatusData = await sourceChainStatusResponse.json(); + const sourceChainStatus = sourceChainStatusData.data ? "healthy" : "error"; + + // Fetch 4: Check destination chain status (simulated via Coinbase system status) + const destChainStatusResponse = await fetch("https://api.coinbase.com/v2/time"); + const destChainStatusData = await destChainStatusResponse.json(); + const destChainStatus = destChainStatusData.data ? "healthy" : "error"; + + return JSON.stringify({ + ethPrice, + bitcoinPrice, + sourceChainStatus, + destChainStatus, + }); + } catch (error) { + console.error('Error fetching price data:', error); + return JSON.stringify({ + error: error.message || "Failed to fetch price data", + }); + } } ); - const { ethPrice, bitcoinPrice, sourceChainStatus, destChainStatus } = JSON.parse(priceDataResult); + const { ethPrice, bitcoinPrice, sourceChainStatus, destChainStatus, error } = JSON.parse(priceDataResult); + + if (error !== undefined) { + Lit.Actions.setResponse({ + response: JSON.stringify({ error }), + }); + return; + } // Calculate swap amounts based on real prices const amountInUsd = parseFloat(swapParams.amountIn) * ethPrice; @@ -88,7 +103,7 @@ async function crossChainSwap() { source: sourceChainStatus, destination: destChainStatus, }, - timestamp: Date.now(), + timestamp: 1718000000000, nonce: 123456789, }; @@ -114,7 +129,7 @@ async function crossChainSwap() { sourceBlockNumber: 18500000, destBlockNumber: 50000000, status: "completed", - executedAt: Date.now(), + executedAt: 1718000000000, }; // Sign 2: Sign the execution proof (like attesting the swap completed on dest chain) diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts index 6a733118f..911d2b111 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts @@ -5,7 +5,6 @@ declare const jsParams: any; * Lit Action: Decrypt within the Lit Action * * Decrypts an API key and makes a fetch request within the Lit Action. - * Runtime: ~5 seconds, Fetches: 1, Decrypts: 1 */ async function decryptWithinLitAction() { const { accessControlConditions, ciphertext, dataToEncryptHash } = jsParams; @@ -22,12 +21,12 @@ async function decryptWithinLitAction() { // Parse the decrypted API key const apiKey = JSON.parse(decryptedApiKey); - // Use the API key in a fetch request - const response = await fetch("https://api.coingecko.com/api/v3/ping", { + // Use the API key in a fetch request (using Coinbase public API) + const response = await fetch("https://api.coinbase.com/v2/time", { method: "GET", headers: { - "Authorization": `Bearer ${apiKey.key}`, "Content-Type": "application/json", + // "Authorization": `Bearer ${apiKey.key}`, }, }); diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts index e0e7dd0ab..b1b648134 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts @@ -5,7 +5,6 @@ declare const ethers: any; * Lit Action: Encrypt and Decrypt within the Lit Action * * Encrypts an API key and decrypts it within the Lit Action. - * Runtime: ~5 seconds, Fetches: 1, Encrypts: 1, Decrypts: 1 */ async function encryptDecryptWithinLitAction() { // First, encrypt an API key (simulating a stored encrypted API key) @@ -52,12 +51,12 @@ async function encryptDecryptWithinLitAction() { // Parse the decrypted API key const apiKey = JSON.parse(decryptedApiKey); - // Use the API key in a fetch request - const response = await fetch("https://api.coingecko.com/api/v3/ping", { + // Use the API key in a fetch request (using Coinbase public API) + const response = await fetch("https://api.coinbase.com/v2/time", { method: "GET", headers: { - "Authorization": `Bearer ${apiKey.key}`, "Content-Type": "application/json", + // "Authorization": `Bearer ${apiKey.key}`, }, }); diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts index a3a0becf1..bbfa27095 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts @@ -5,7 +5,6 @@ declare const ethers: any; * Lit Action: Oracle Operation * * Fetches external data and signs the result using broadcastAndCollect to medianize prices. - * Runtime: ~10 seconds, Fetches: 1, Signatures: 1, Decrypts: 0 */ async function oracleOperation() { // Helper function to calculate median @@ -16,16 +15,16 @@ async function oracleOperation() { : arrSorted[Math.floor(arrSorted.length / 2)]; }; - // Fetch external data (e.g., price oracle data) + // Fetch external data (e.g., price oracle data from Coinbase) const response = await fetch( - "https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd" + "https://api.coinbase.com/v2/prices/ETH-USD/spot" ); const data = await response.json(); // Collect prices from all the nodes const allPrices = await Lit.Actions.broadcastAndCollect({ name: "ethPrice", - value: data.ethereum.usd.toString(), + value: data.data.amount, }); // Medianize the price, so that outliers don't skew the result diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/verifiableDataJob.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/verifiableDataJob.ts index 3c3bf7104..5908fe672 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/verifiableDataJob.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/verifiableDataJob.ts @@ -6,7 +6,6 @@ declare const jsParams: any; * Lit Action: Verifiable Data Job * * Processes data locally and signs the result to create a verifiable attestation. - * Runtime: ~45 seconds, Fetches: 0, Signatures: 1, Decrypts: 0 */ async function verifiableDataJob() { // Generate and process data locally (using runOnce to ensure it only runs on one node) @@ -42,14 +41,14 @@ async function verifiableDataJob() { console.log('aggregatedData', aggregatedData); // Simulate processing time - await new Promise((resolve) => setTimeout(resolve, 45000)); + await new Promise((resolve) => setTimeout(resolve, 25000)); - // Sign the processed result - const toSign = ethers.utils.arrayify( - ethers.utils.keccak256(ethers.utils.toUtf8Bytes(JSON.stringify(aggregatedData))) + // Sign the processed result - hash the data first, then convert to bytes + const dataHash = ethers.utils.keccak256( + ethers.utils.toUtf8Bytes(JSON.stringify(aggregatedData)) ); await Lit.Actions.signEcdsa({ - toSign, + toSign: ethers.utils.arrayify(dataHash), publicKey: jsParams.pkpPublicKey, sigName: "verifiable-data-signature", }); diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts index f3bff0801..d8caaf56a 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts @@ -17,9 +17,20 @@ const stringifyWithBigInt = (value: unknown) => 2 ); +type PaymentSummary = { + testName: string; + components: Array<{ + component: string; + quantity: number; + price: bigint; + }>; + totalCost: bigint; +}; + export const registerPaymentBenchmarkTests = () => { let testEnv: Awaited>; let benchmarkUser: CreateTestAccountResult; + const paymentSummaries: PaymentSummary[] = []; beforeAll(async () => { const envVars = createEnvVars(); @@ -37,12 +48,48 @@ export const registerPaymentBenchmarkTests = () => { hasPKP: true, fundPKP: false, hasPKPAuthContext: false, - fundPKPLedger: true, + fundPKPLedger: false, }); }, 120000); // Increased timeout for setup + afterAll(() => { + if (paymentSummaries.length > 0) { + paymentSummaries.forEach((summary, index) => { + // Use a single console.log with console.table to title the table + const tableTitle = `${summary.testName}`; + + // Create table data + const tableData = summary.components.map(comp => ({ + Component: comp.component, + Quantity: comp.quantity, + 'Price (wei)': comp.price.toString(), + 'Price (tstLPX)': (Number(comp.price) / 1e18).toFixed(10), + })); + + // Add total row + const totalInTstLPX = (Number(summary.totalCost) / 1e18).toFixed(10); + tableData.push({ + Component: '**TOTAL**', + Quantity: 0, + 'Price (wei)': summary.totalCost.toString(), + 'Price (tstLPX)': totalInTstLPX, + }); + + // Title above table and table itself in one group for readability + console.group(tableTitle); + console.table(tableData); + console.groupEnd(); + }); + + // Grand total + const grandTotal = paymentSummaries.reduce((sum, s) => sum + s.totalCost, 0n); + const grandTotalInTstLPX = (Number(grandTotal) / 1e18).toFixed(10); + console.log(`GRAND TOTAL (ALL TESTS): ${grandTotal.toString()} wei (${grandTotalInTstLPX} tstLPX)`); + } + }); + describe('Payment Benchmark Tests', () => { - describe.skip('Secure API Key Usage', () => { + describe('Secure API Key Usage', () => { test('should encrypt outside the Lit Action, and decrypt and make a fetch request inside the Lit Action', async () => { // Encrypt the API key outside the Lit Action (simulating a pre-encrypted stored API key) const apiKeyData = JSON.stringify({ key: "example-api-key-12345" }); @@ -100,6 +147,17 @@ export const registerPaymentBenchmarkTests = () => { return sum + entry.price; }, 0n); console.log(`\nTotal Cost: ${totalCost.toString()}`); + + // Add to summary + paymentSummaries.push({ + testName: 'Decrypt within Lit Action (5s, 3 fetches, 3 decrypts)', + components: paymentDetail.map(entry => ({ + component: entry.component, + quantity: entry.quantity, + price: entry.price, + })), + totalCost, + }); }, 120000); // 2 minute timeout test('should encrypt, decrypt and make a fetch request within the Lit Action', async () => { @@ -130,13 +188,22 @@ export const registerPaymentBenchmarkTests = () => { return sum + entry.price; }, 0n); console.log(`\nTotal Cost: ${totalCost.toString()}`); + + // Add to summary + paymentSummaries.push({ + testName: 'Encrypt & Decrypt within Lit Action (5s, 3 fetches, 1 encrypt, 3 decrypts)', + components: paymentDetail.map(entry => ({ + component: entry.component, + quantity: entry.quantity, + price: entry.price, + })), + totalCost, + }); }, 120000); // 2 minute timeout }); - describe.skip('Verifiable Data Job', () => { + describe('Verifiable Data Job', () => { test('should process data and sign the result', async () => { - console.log('benchmarkUser', benchmarkUser); - const executionResult = await testEnv.litClient.executeJs({ code: VERIFIABLE_DATA_JOB_LIT_ACTION, authContext: benchmarkUser.eoaAuthContext!, @@ -144,7 +211,6 @@ export const registerPaymentBenchmarkTests = () => { pkpPublicKey: benchmarkUser.pkp!.pubkey, }, }); - console.log('executionResult', executionResult); // Verify successful execution @@ -173,17 +239,27 @@ export const registerPaymentBenchmarkTests = () => { return sum + entry.price; }, 0n); console.log(`\nTotal Cost: ${totalCost.toString()}`); + + // Add to summary + paymentSummaries.push({ + testName: 'Verifiable Data Job (45s, 0 fetches, 1 signature)', + components: paymentDetail.map(entry => ({ + component: entry.component, + quantity: entry.quantity, + price: entry.price, + })), + totalCost, + }); }, 120000); // 2 minute timeout }); - describe.skip('Oracle Operation', () => { + describe('Oracle Operation', () => { test('should fetch external data, medianize prices, and sign the result', async () => { const executionResult = await testEnv.litClient.executeJs({ code: ORACLE_OPERATION_LIT_ACTION, authContext: benchmarkUser.eoaAuthContext!, jsParams: {}, }); - console.log('executionResult', executionResult); // Verify successful execution @@ -211,6 +287,17 @@ export const registerPaymentBenchmarkTests = () => { return sum + entry.price; }, 0n); console.log(`\nTotal Cost: ${totalCost.toString()}`); + + // Add to summary + paymentSummaries.push({ + testName: 'Oracle Operation (10s, 3 fetches, 3 signatures)', + components: paymentDetail.map(entry => ({ + component: entry.component, + quantity: entry.quantity, + price: entry.price, + })), + totalCost, + }); }, 120000); // 2 minute timeout }); @@ -276,7 +363,18 @@ export const registerPaymentBenchmarkTests = () => { return sum + entry.price; }, 0n); console.log(`\nTotal Cost: ${totalCost.toString()}`); - }, 120000); // 2 minute timeout + + // Add to summary + paymentSummaries.push({ + testName: 'Cross-Chain Swap (20s, 4 fetches, 6 signatures)', + components: paymentDetail.map(entry => ({ + component: entry.component, + quantity: entry.quantity, + price: entry.price, + })), + totalCost, + }); + }, 240000); // 4 minute timeout }); }); }; From 123b5000fc5466c986a87981002a5881ace26df3 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 18 Dec 2025 15:15:46 -1000 Subject: [PATCH 10/17] chore: remove details from testName --- .../executeJs/paymentBenchmarks/paymentBenchmark.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts index d8caaf56a..251f1efb1 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts @@ -150,7 +150,7 @@ export const registerPaymentBenchmarkTests = () => { // Add to summary paymentSummaries.push({ - testName: 'Decrypt within Lit Action (5s, 3 fetches, 3 decrypts)', + testName: 'Decrypt within Lit Action', components: paymentDetail.map(entry => ({ component: entry.component, quantity: entry.quantity, @@ -191,7 +191,7 @@ export const registerPaymentBenchmarkTests = () => { // Add to summary paymentSummaries.push({ - testName: 'Encrypt & Decrypt within Lit Action (5s, 3 fetches, 1 encrypt, 3 decrypts)', + testName: 'Encrypt & Decrypt within Lit Action', components: paymentDetail.map(entry => ({ component: entry.component, quantity: entry.quantity, @@ -242,7 +242,7 @@ export const registerPaymentBenchmarkTests = () => { // Add to summary paymentSummaries.push({ - testName: 'Verifiable Data Job (45s, 0 fetches, 1 signature)', + testName: 'Verifiable Data Job', components: paymentDetail.map(entry => ({ component: entry.component, quantity: entry.quantity, @@ -290,7 +290,7 @@ export const registerPaymentBenchmarkTests = () => { // Add to summary paymentSummaries.push({ - testName: 'Oracle Operation (10s, 3 fetches, 3 signatures)', + testName: 'Oracle Operation', components: paymentDetail.map(entry => ({ component: entry.component, quantity: entry.quantity, @@ -366,7 +366,7 @@ export const registerPaymentBenchmarkTests = () => { // Add to summary paymentSummaries.push({ - testName: 'Cross-Chain Swap (20s, 4 fetches, 6 signatures)', + testName: 'Cross-Chain Swap', components: paymentDetail.map(entry => ({ component: entry.component, quantity: entry.quantity, From 1a2b080ca723d53ee2162b88d154be3d03c83720 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 18 Dec 2025 15:25:32 -1000 Subject: [PATCH 11/17] chore: ran linter --- packages/e2e/src/helper/createTestAccount.ts | 4 +- .../litActions/crossChainSwap.ts | 54 ++++---- .../litActions/decryptWithinLitAction.ts | 8 +- .../encryptDecryptWithinLitAction.ts | 116 +++++++++--------- .../litActions/oracleOperation.ts | 12 +- .../litActions/verifiableDataJob.ts | 13 +- .../paymentBenchmarks/paymentBenchmark.ts | 61 +++++---- 7 files changed, 152 insertions(+), 116 deletions(-) diff --git a/packages/e2e/src/helper/createTestAccount.ts b/packages/e2e/src/helper/createTestAccount.ts index 92bfe298a..94642fdd4 100644 --- a/packages/e2e/src/helper/createTestAccount.ts +++ b/packages/e2e/src/helper/createTestAccount.ts @@ -74,7 +74,9 @@ export async function createTestAccount( console.log(`Address`, person.account.address); console.log(`opts:`, { ...opts, - privateKey: opts.privateKey ? (opts.privateKey.slice(0, 6) + '...') : undefined, + privateKey: opts.privateKey + ? opts.privateKey.slice(0, 6) + '...' + : undefined, }); // 3. fund it diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts index 957ebc514..f07c43d8f 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts @@ -11,23 +11,23 @@ declare const jsParams: any; async function crossChainSwap() { // Swap parameters (in a real scenario, these would come from jsParams) const swapParams = { - sourceChain: "ethereum", - destChain: "bitcoin", - sourceToken: "ETH", - destToken: "BTC", - amountIn: "1.0", // 1 ETH - userAddress: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", // Example address + sourceChain: 'ethereum', + destChain: 'bitcoin', + sourceToken: 'ETH', + destToken: 'BTC', + amountIn: '1.0', // 1 ETH + userAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', // Example address slippageTolerance: 0.5, // 0.5% }; // Fetch prices and chain status (using runOnce to ensure consistent data across all nodes) const priceDataResult = await Lit.Actions.runOnce( - { waitForResponse: true, name: "fetchPriceData" }, + { waitForResponse: true, name: 'fetchPriceData' }, async () => { try { // Fetch 1: Get source token price (ETH) from Coinbase const ethPriceResponse = await fetch( - "https://api.coinbase.com/v2/prices/ETH-USD/buy" + 'https://api.coinbase.com/v2/prices/ETH-USD/buy' ); const ethPriceData = await ethPriceResponse.json(); console.log('ethPriceData', ethPriceData); @@ -35,21 +35,27 @@ async function crossChainSwap() { // Fetch 2: Get destination token price (BTC) from Coinbase const bitcoinPriceResponse = await fetch( - "https://api.coinbase.com/v2/prices/BTC-USD/buy" + 'https://api.coinbase.com/v2/prices/BTC-USD/buy' ); const bitcoinPriceData = await bitcoinPriceResponse.json(); console.log('bitcoinPriceData', bitcoinPriceData); const bitcoinPrice = parseFloat(bitcoinPriceData.data.amount); // Fetch 3: Check source chain status (simulated via Coinbase system status) - const sourceChainStatusResponse = await fetch("https://api.coinbase.com/v2/time"); + const sourceChainStatusResponse = await fetch( + 'https://api.coinbase.com/v2/time' + ); const sourceChainStatusData = await sourceChainStatusResponse.json(); - const sourceChainStatus = sourceChainStatusData.data ? "healthy" : "error"; + const sourceChainStatus = sourceChainStatusData.data + ? 'healthy' + : 'error'; // Fetch 4: Check destination chain status (simulated via Coinbase system status) - const destChainStatusResponse = await fetch("https://api.coinbase.com/v2/time"); + const destChainStatusResponse = await fetch( + 'https://api.coinbase.com/v2/time' + ); const destChainStatusData = await destChainStatusResponse.json(); - const destChainStatus = destChainStatusData.data ? "healthy" : "error"; + const destChainStatus = destChainStatusData.data ? 'healthy' : 'error'; return JSON.stringify({ ethPrice, @@ -60,13 +66,14 @@ async function crossChainSwap() { } catch (error) { console.error('Error fetching price data:', error); return JSON.stringify({ - error: error.message || "Failed to fetch price data", + error: error.message || 'Failed to fetch price data', }); } } ); - const { ethPrice, bitcoinPrice, sourceChainStatus, destChainStatus, error } = JSON.parse(priceDataResult); + const { ethPrice, bitcoinPrice, sourceChainStatus, destChainStatus, error } = + JSON.parse(priceDataResult); if (error !== undefined) { Lit.Actions.setResponse({ @@ -84,7 +91,8 @@ async function crossChainSwap() { const actualSlippage = 0.2; // 0.2% actual slippage (within tolerance) const feesAndSlippage = (bridgeFeePercent + actualSlippage) / 100; const amountOutAfterFees = expectedAmountOut * (1 - feesAndSlippage); - const minAmountOut = expectedAmountOut * (1 - swapParams.slippageTolerance / 100); + const minAmountOut = + expectedAmountOut * (1 - swapParams.slippageTolerance / 100); // Prepare swap intent data const swapIntent = { @@ -114,7 +122,7 @@ async function crossChainSwap() { await Lit.Actions.signEcdsa({ toSign: ethers.utils.arrayify(swapIntentHash), publicKey: jsParams.pkpPublicKey, - sigName: "swap-approval-signature", + sigName: 'swap-approval-signature', }); // Simulate cross-chain bridge processing time (waiting for confirmations, relayers, etc.) @@ -124,11 +132,15 @@ async function crossChainSwap() { const executionProof = { swapIntentHash: swapIntentHash, executedAmountOut: amountOutAfterFees.toString(), - sourceTxHash: ethers.utils.keccak256(ethers.utils.toUtf8Bytes(`source-${swapIntent.nonce}`)), - destTxHash: ethers.utils.keccak256(ethers.utils.toUtf8Bytes(`dest-${swapIntent.nonce}`)), + sourceTxHash: ethers.utils.keccak256( + ethers.utils.toUtf8Bytes(`source-${swapIntent.nonce}`) + ), + destTxHash: ethers.utils.keccak256( + ethers.utils.toUtf8Bytes(`dest-${swapIntent.nonce}`) + ), sourceBlockNumber: 18500000, destBlockNumber: 50000000, - status: "completed", + status: 'completed', executedAt: 1718000000000, }; @@ -139,7 +151,7 @@ async function crossChainSwap() { await Lit.Actions.signEcdsa({ toSign: ethers.utils.arrayify(executionProofHash), publicKey: jsParams.pkpPublicKey, - sigName: "swap-execution-signature", + sigName: 'swap-execution-signature', }); // Simulate remaining runtime to reach 20 seconds total diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts index 911d2b111..40b5c6045 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/decryptWithinLitAction.ts @@ -15,17 +15,17 @@ async function decryptWithinLitAction() { ciphertext, dataToEncryptHash, authSig: null, - chain: "ethereum", + chain: 'ethereum', }); // Parse the decrypted API key const apiKey = JSON.parse(decryptedApiKey); // Use the API key in a fetch request (using Coinbase public API) - const response = await fetch("https://api.coinbase.com/v2/time", { - method: "GET", + const response = await fetch('https://api.coinbase.com/v2/time', { + method: 'GET', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', // "Authorization": `Bearer ${apiKey.key}`, }, }); diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts index b1b648134..5d325f33f 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/encryptDecryptWithinLitAction.ts @@ -7,72 +7,72 @@ declare const ethers: any; * Encrypts an API key and decrypts it within the Lit Action. */ async function encryptDecryptWithinLitAction() { - // First, encrypt an API key (simulating a stored encrypted API key) - // In a real scenario, this would already be encrypted and stored - const apiKeyData = JSON.stringify({ key: "example-api-key-12345" }); - const currentCid = Lit.Auth.actionIpfsIdStack[0]; + // First, encrypt an API key (simulating a stored encrypted API key) + // In a real scenario, this would already be encrypted and stored + const apiKeyData = JSON.stringify({ key: 'example-api-key-12345' }); + const currentCid = Lit.Auth.actionIpfsIdStack[0]; - const accessControlConditions = [ - { - contractAddress: "", - standardContractType: "", - chain: "ethereum", - method: "", - parameters: [":currentActionIpfsId"], - returnValueTest: { - comparator: "=", - value: currentCid, - }, - }, - ]; + const accessControlConditions = [ + { + contractAddress: '', + standardContractType: '', + chain: 'ethereum', + method: '', + parameters: [':currentActionIpfsId'], + returnValueTest: { + comparator: '=', + value: currentCid, + }, + }, + ]; - // Encrypt the API key (using runOnce to ensure it only runs on one node) - const encryptResult = await Lit.Actions.runOnce( - { waitForResponse: true, name: "encryptApiKey" }, - async () => { - const result = await Lit.Actions.encrypt({ - accessControlConditions, - to_encrypt: ethers.utils.toUtf8Bytes(apiKeyData), - }); - return JSON.stringify(result); - } - ); - const { ciphertext, dataToEncryptHash } = JSON.parse(encryptResult); - - // Now decrypt the API key (this is the actual decrypt operation we're counting) - const decryptedApiKey = await Lit.Actions.decryptAndCombine({ + // Encrypt the API key (using runOnce to ensure it only runs on one node) + const encryptResult = await Lit.Actions.runOnce( + { waitForResponse: true, name: 'encryptApiKey' }, + async () => { + const result = await Lit.Actions.encrypt({ accessControlConditions, - ciphertext, - dataToEncryptHash, - authSig: null, - chain: "ethereum", - }); + to_encrypt: ethers.utils.toUtf8Bytes(apiKeyData), + }); + return JSON.stringify(result); + } + ); + const { ciphertext, dataToEncryptHash } = JSON.parse(encryptResult); + + // Now decrypt the API key (this is the actual decrypt operation we're counting) + const decryptedApiKey = await Lit.Actions.decryptAndCombine({ + accessControlConditions, + ciphertext, + dataToEncryptHash, + authSig: null, + chain: 'ethereum', + }); - // Parse the decrypted API key - const apiKey = JSON.parse(decryptedApiKey); + // Parse the decrypted API key + const apiKey = JSON.parse(decryptedApiKey); - // Use the API key in a fetch request (using Coinbase public API) - const response = await fetch("https://api.coinbase.com/v2/time", { - method: "GET", - headers: { - "Content-Type": "application/json", - // "Authorization": `Bearer ${apiKey.key}`, - }, - }); + // Use the API key in a fetch request (using Coinbase public API) + const response = await fetch('https://api.coinbase.com/v2/time', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + // "Authorization": `Bearer ${apiKey.key}`, + }, + }); - const responseData = await response.json(); + const responseData = await response.json(); - // Simulate runtime of 5 seconds - await new Promise((resolve) => setTimeout(resolve, 5000)); + // Simulate runtime of 5 seconds + await new Promise((resolve) => setTimeout(resolve, 5000)); - Lit.Actions.setResponse({ - response: JSON.stringify({ - success: true, - data: responseData, - // Note: We don't expose the actual API key in the response - }), - }); + Lit.Actions.setResponse({ + response: JSON.stringify({ + success: true, + data: responseData, + // Note: We don't expose the actual API key in the response + }), + }); } // Convert the function to a string and wrap it in an IIFE -export const ENCRYPT_DECRYPT_WITHIN_LIT_ACTION = `(${encryptDecryptWithinLitAction.toString()})();`; \ No newline at end of file +export const ENCRYPT_DECRYPT_WITHIN_LIT_ACTION = `(${encryptDecryptWithinLitAction.toString()})();`; diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts index bbfa27095..54fcb4eab 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts @@ -11,19 +11,21 @@ async function oracleOperation() { const median = (arr: number[]) => { const arrSorted = arr.sort((a, b) => a - b); return arrSorted.length % 2 === 0 - ? (arrSorted[arrSorted.length / 2 - 1] + arrSorted[arrSorted.length / 2]) / 2 + ? (arrSorted[arrSorted.length / 2 - 1] + + arrSorted[arrSorted.length / 2]) / + 2 : arrSorted[Math.floor(arrSorted.length / 2)]; }; // Fetch external data (e.g., price oracle data from Coinbase) const response = await fetch( - "https://api.coinbase.com/v2/prices/ETH-USD/spot" + 'https://api.coinbase.com/v2/prices/ETH-USD/spot' ); const data = await response.json(); // Collect prices from all the nodes const allPrices = await Lit.Actions.broadcastAndCollect({ - name: "ethPrice", + name: 'ethPrice', value: data.data.amount, }); @@ -39,8 +41,8 @@ async function oracleOperation() { const toSign = ethers.utils.arrayify(priceHash); await Lit.Actions.signAsAction({ toSign, - signingScheme: "EcdsaK256Sha256", - sigName: "oracle-signature", + signingScheme: 'EcdsaK256Sha256', + sigName: 'oracle-signature', }); // Simulate runtime of 10 seconds diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/verifiableDataJob.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/verifiableDataJob.ts index 5908fe672..caf188e09 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/verifiableDataJob.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/verifiableDataJob.ts @@ -10,7 +10,7 @@ declare const jsParams: any; async function verifiableDataJob() { // Generate and process data locally (using runOnce to ensure it only runs on one node) const dataResult = await Lit.Actions.runOnce( - { waitForResponse: true, name: "generateData" }, + { waitForResponse: true, name: 'generateData' }, async () => { const dataPoints = []; for (let i = 0; i < 1000; i++) { @@ -19,16 +19,19 @@ async function verifiableDataJob() { dataPoints.push({ index: i, value: processedValue, - hash: ethers.utils.keccak256(ethers.utils.toUtf8Bytes(processedValue.toString())), + hash: ethers.utils.keccak256( + ethers.utils.toUtf8Bytes(processedValue.toString()) + ), }); } // Aggregate the processed data const aggregatedData = { totalPoints: dataPoints.length, - averageValue: dataPoints.reduce((sum, p) => sum + p.value, 0) / dataPoints.length, + averageValue: + dataPoints.reduce((sum, p) => sum + p.value, 0) / dataPoints.length, dataHash: ethers.utils.keccak256( - ethers.utils.toUtf8Bytes(dataPoints.map(p => p.hash).join("")) + ethers.utils.toUtf8Bytes(dataPoints.map((p) => p.hash).join('')) ), timestamp: Date.now(), }; @@ -50,7 +53,7 @@ async function verifiableDataJob() { await Lit.Actions.signEcdsa({ toSign: ethers.utils.arrayify(dataHash), publicKey: jsParams.pkpPublicKey, - sigName: "verifiable-data-signature", + sigName: 'verifiable-data-signature', }); Lit.Actions.setResponse({ diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts index 251f1efb1..ccbd00b67 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts @@ -37,7 +37,9 @@ export const registerPaymentBenchmarkTests = () => { testEnv = await createTestEnv(envVars); // Use TEST_ALICE_PRIVATE_KEY if available to reuse the same account across test runs - const privateKey = process.env['TEST_ALICE_PRIVATE_KEY'] as `0x${string}` | undefined; + const privateKey = process.env['TEST_ALICE_PRIVATE_KEY'] as + | `0x${string}` + | undefined; benchmarkUser = await createTestAccount(testEnv, { label: 'Payment Benchmark User', @@ -59,7 +61,7 @@ export const registerPaymentBenchmarkTests = () => { const tableTitle = `${summary.testName}`; // Create table data - const tableData = summary.components.map(comp => ({ + const tableData = summary.components.map((comp) => ({ Component: comp.component, Quantity: comp.quantity, 'Price (wei)': comp.price.toString(), @@ -82,9 +84,14 @@ export const registerPaymentBenchmarkTests = () => { }); // Grand total - const grandTotal = paymentSummaries.reduce((sum, s) => sum + s.totalCost, 0n); + const grandTotal = paymentSummaries.reduce( + (sum, s) => sum + s.totalCost, + 0n + ); const grandTotalInTstLPX = (Number(grandTotal) / 1e18).toFixed(10); - console.log(`GRAND TOTAL (ALL TESTS): ${grandTotal.toString()} wei (${grandTotalInTstLPX} tstLPX)`); + console.log( + `GRAND TOTAL (ALL TESTS): ${grandTotal.toString()} wei (${grandTotalInTstLPX} tstLPX)` + ); } }); @@ -92,19 +99,19 @@ export const registerPaymentBenchmarkTests = () => { describe('Secure API Key Usage', () => { test('should encrypt outside the Lit Action, and decrypt and make a fetch request inside the Lit Action', async () => { // Encrypt the API key outside the Lit Action (simulating a pre-encrypted stored API key) - const apiKeyData = JSON.stringify({ key: "example-api-key-12345" }); + const apiKeyData = JSON.stringify({ key: 'example-api-key-12345' }); // Create always-true access control conditions for the benchmark const accessControlConditions = [ { - contractAddress: "", - standardContractType: "" as const, - chain: "ethereum" as const, - method: "", - parameters: ["1"], + contractAddress: '', + standardContractType: '' as const, + chain: 'ethereum' as const, + method: '', + parameters: ['1'], returnValueTest: { - comparator: "=" as const, - value: "1", + comparator: '=' as const, + value: '1', }, }, ]; @@ -151,7 +158,7 @@ export const registerPaymentBenchmarkTests = () => { // Add to summary paymentSummaries.push({ testName: 'Decrypt within Lit Action', - components: paymentDetail.map(entry => ({ + components: paymentDetail.map((entry) => ({ component: entry.component, quantity: entry.quantity, price: entry.price, @@ -192,7 +199,7 @@ export const registerPaymentBenchmarkTests = () => { // Add to summary paymentSummaries.push({ testName: 'Encrypt & Decrypt within Lit Action', - components: paymentDetail.map(entry => ({ + components: paymentDetail.map((entry) => ({ component: entry.component, quantity: entry.quantity, price: entry.price, @@ -223,7 +230,9 @@ export const registerPaymentBenchmarkTests = () => { expect(response.aggregatedData.timestamp).toBeGreaterThan(0); expect(executionResult.signatures).toBeDefined(); - expect(executionResult.signatures['verifiable-data-signature']).toBeDefined(); + expect( + executionResult.signatures['verifiable-data-signature'] + ).toBeDefined(); // Verify payment details are returned expect(executionResult.paymentDetail).toBeDefined(); @@ -243,7 +252,7 @@ export const registerPaymentBenchmarkTests = () => { // Add to summary paymentSummaries.push({ testName: 'Verifiable Data Job', - components: paymentDetail.map(entry => ({ + components: paymentDetail.map((entry) => ({ component: entry.component, quantity: entry.quantity, price: entry.price, @@ -291,7 +300,7 @@ export const registerPaymentBenchmarkTests = () => { // Add to summary paymentSummaries.push({ testName: 'Oracle Operation', - components: paymentDetail.map(entry => ({ + components: paymentDetail.map((entry) => ({ component: entry.component, quantity: entry.quantity, price: entry.price, @@ -328,8 +337,12 @@ export const registerPaymentBenchmarkTests = () => { expect(response.swapIntent.pricing).toBeDefined(); expect(response.swapIntent.pricing.ethPrice).toBeGreaterThan(0); expect(response.swapIntent.pricing.bitcoinPrice).toBeGreaterThan(0); - expect(response.swapIntent.pricing.expectedAmountOut).toBeGreaterThan(0); - expect(response.swapIntent.pricing.amountOutAfterFees).toBeGreaterThan(0); + expect(response.swapIntent.pricing.expectedAmountOut).toBeGreaterThan( + 0 + ); + expect(response.swapIntent.pricing.amountOutAfterFees).toBeGreaterThan( + 0 + ); expect(response.swapIntent.pricing.amountOutAfterFees).toBeLessThan( response.swapIntent.pricing.expectedAmountOut ); // Fees should reduce output @@ -346,8 +359,12 @@ export const registerPaymentBenchmarkTests = () => { // Verify both signatures were created (approval + execution) expect(executionResult.signatures).toBeDefined(); - expect(executionResult.signatures['swap-approval-signature']).toBeDefined(); - expect(executionResult.signatures['swap-execution-signature']).toBeDefined(); + expect( + executionResult.signatures['swap-approval-signature'] + ).toBeDefined(); + expect( + executionResult.signatures['swap-execution-signature'] + ).toBeDefined(); // Verify payment details are returned expect(executionResult.paymentDetail).toBeDefined(); @@ -367,7 +384,7 @@ export const registerPaymentBenchmarkTests = () => { // Add to summary paymentSummaries.push({ testName: 'Cross-Chain Swap', - components: paymentDetail.map(entry => ({ + components: paymentDetail.map((entry) => ({ component: entry.component, quantity: entry.quantity, price: entry.price, From 9470d30e1842ac90f4467189939df8a56798ef87 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 18 Dec 2025 15:36:39 -1000 Subject: [PATCH 12/17] chore: dedupe payment summary code --- .../paymentBenchmarks/paymentBenchmark.ts | 129 +++++------------- 1 file changed, 34 insertions(+), 95 deletions(-) diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts index ccbd00b67..b55242f99 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/paymentBenchmark.ts @@ -32,6 +32,32 @@ export const registerPaymentBenchmarkTests = () => { let benchmarkUser: CreateTestAccountResult; const paymentSummaries: PaymentSummary[] = []; + // Helper function to process and log payment details + const logAndSavePaymentDetails = ( + testName: string, + paymentDetail: Array<{ component: string; quantity: number; price: bigint }> + ) => { + console.log('\nPayment Details:'); + console.log(stringifyWithBigInt(paymentDetail)); + + // Calculate total cost + const totalCost = paymentDetail.reduce((sum, entry) => { + return sum + entry.price; + }, 0n); + console.log(`\nTotal Cost: ${totalCost.toString()}`); + + // Add to summary + paymentSummaries.push({ + testName, + components: paymentDetail.map((entry) => ({ + component: entry.component, + quantity: entry.quantity, + price: entry.price, + })), + totalCost, + }); + }; + beforeAll(async () => { const envVars = createEnvVars(); testEnv = await createTestEnv(envVars); @@ -146,25 +172,7 @@ export const registerPaymentBenchmarkTests = () => { const paymentDetail = executionResult.paymentDetail!; console.log(executionResult); - console.log('\nPayment Details:'); - console.log(stringifyWithBigInt(paymentDetail)); - - // Calculate total cost - const totalCost = paymentDetail.reduce((sum, entry) => { - return sum + entry.price; - }, 0n); - console.log(`\nTotal Cost: ${totalCost.toString()}`); - - // Add to summary - paymentSummaries.push({ - testName: 'Decrypt within Lit Action', - components: paymentDetail.map((entry) => ({ - component: entry.component, - quantity: entry.quantity, - price: entry.price, - })), - totalCost, - }); + logAndSavePaymentDetails('Decrypt within Lit Action', paymentDetail); }, 120000); // 2 minute timeout test('should encrypt, decrypt and make a fetch request within the Lit Action', async () => { @@ -187,25 +195,10 @@ export const registerPaymentBenchmarkTests = () => { expect(executionResult.paymentDetail!.length).toBeGreaterThan(0); const paymentDetail = executionResult.paymentDetail!; - console.log('\nPayment Details:'); - console.log(stringifyWithBigInt(paymentDetail)); - - // Calculate total cost - const totalCost = paymentDetail.reduce((sum, entry) => { - return sum + entry.price; - }, 0n); - console.log(`\nTotal Cost: ${totalCost.toString()}`); - - // Add to summary - paymentSummaries.push({ - testName: 'Encrypt & Decrypt within Lit Action', - components: paymentDetail.map((entry) => ({ - component: entry.component, - quantity: entry.quantity, - price: entry.price, - })), - totalCost, - }); + logAndSavePaymentDetails( + 'Encrypt & Decrypt within Lit Action', + paymentDetail + ); }, 120000); // 2 minute timeout }); @@ -240,25 +233,7 @@ export const registerPaymentBenchmarkTests = () => { expect(executionResult.paymentDetail!.length).toBeGreaterThan(0); const paymentDetail = executionResult.paymentDetail!; - console.log('\nPayment Details:'); - console.log(stringifyWithBigInt(paymentDetail)); - - // Calculate total cost - const totalCost = paymentDetail.reduce((sum, entry) => { - return sum + entry.price; - }, 0n); - console.log(`\nTotal Cost: ${totalCost.toString()}`); - - // Add to summary - paymentSummaries.push({ - testName: 'Verifiable Data Job', - components: paymentDetail.map((entry) => ({ - component: entry.component, - quantity: entry.quantity, - price: entry.price, - })), - totalCost, - }); + logAndSavePaymentDetails('Verifiable Data Job', paymentDetail); }, 120000); // 2 minute timeout }); @@ -288,25 +263,7 @@ export const registerPaymentBenchmarkTests = () => { expect(executionResult.paymentDetail!.length).toBeGreaterThan(0); const paymentDetail = executionResult.paymentDetail!; - console.log('\nPayment Details:'); - console.log(stringifyWithBigInt(paymentDetail)); - - // Calculate total cost - const totalCost = paymentDetail.reduce((sum, entry) => { - return sum + entry.price; - }, 0n); - console.log(`\nTotal Cost: ${totalCost.toString()}`); - - // Add to summary - paymentSummaries.push({ - testName: 'Oracle Operation', - components: paymentDetail.map((entry) => ({ - component: entry.component, - quantity: entry.quantity, - price: entry.price, - })), - totalCost, - }); + logAndSavePaymentDetails('Oracle Operation', paymentDetail); }, 120000); // 2 minute timeout }); @@ -372,25 +329,7 @@ export const registerPaymentBenchmarkTests = () => { expect(executionResult.paymentDetail!.length).toBeGreaterThan(0); const paymentDetail = executionResult.paymentDetail!; - console.log('\nPayment Details:'); - console.log(stringifyWithBigInt(paymentDetail)); - - // Calculate total cost - const totalCost = paymentDetail.reduce((sum, entry) => { - return sum + entry.price; - }, 0n); - console.log(`\nTotal Cost: ${totalCost.toString()}`); - - // Add to summary - paymentSummaries.push({ - testName: 'Cross-Chain Swap', - components: paymentDetail.map((entry) => ({ - component: entry.component, - quantity: entry.quantity, - price: entry.price, - })), - totalCost, - }); + logAndSavePaymentDetails('Cross-Chain Swap', paymentDetail); }, 240000); // 4 minute timeout }); }); From 275b5b007187c258a23f8c1995c45c9dc70ae74e Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 18 Dec 2025 16:06:44 -1000 Subject: [PATCH 13/17] chore: upped funding amount for e2e tests --- packages/e2e/src/helper/createTestEnv.ts | 4 ++-- packages/e2e/src/init.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/e2e/src/helper/createTestEnv.ts b/packages/e2e/src/helper/createTestEnv.ts index 4b409abef..8f143ea2c 100644 --- a/packages/e2e/src/helper/createTestEnv.ts +++ b/packages/e2e/src/helper/createTestEnv.ts @@ -27,7 +27,7 @@ export const CONFIG = { }, }, LIVE: { - nativeFundingAmount: '0.1', + nativeFundingAmount: '0.2', ledgerDepositAmount: '10', sponsorshipLimits: { totalMaxPriceInWei: '50000000000000000', @@ -35,7 +35,7 @@ export const CONFIG = { }, }, MAINNET: { - nativeFundingAmount: '0.01', + nativeFundingAmount: '0.2', ledgerDepositAmount: '0.01', sponsorshipLimits: { totalMaxPriceInWei: '10000000000000000', diff --git a/packages/e2e/src/init.ts b/packages/e2e/src/init.ts index cfdd3f7dc..7cb6f970f 100644 --- a/packages/e2e/src/init.ts +++ b/packages/e2e/src/init.ts @@ -40,10 +40,10 @@ const LogLevelSchema = z.enum(['silent', 'info', 'debug']); type LogLevel = z.infer; // Configurations -const LIVE_NETWORK_FUNDING_AMOUNT = '0.01'; +const LIVE_NETWORK_FUNDING_AMOUNT = '0.2'; const LOCAL_NETWORK_FUNDING_AMOUNT = '1'; const LIVE_NETWORK_LEDGER_DEPOSIT_AMOUNT = '1'; -const MAINNET_NETWORK_FUNDING_AMOUNT = '0.01'; +const MAINNET_NETWORK_FUNDING_AMOUNT = '0.2'; const MAINNET_LEDGER_DEPOSIT_AMOUNT = '0.01'; const EVE_VALIDATION_IPFS_CID = From 794fbf1b3b28a9d2ad4cab891cb27ee09d347196 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 18 Dec 2025 16:25:21 -1000 Subject: [PATCH 14/17] chore: debugging fund amount --- packages/e2e/src/helper/createTestEnv.ts | 4 ++-- packages/e2e/src/init.ts | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/e2e/src/helper/createTestEnv.ts b/packages/e2e/src/helper/createTestEnv.ts index 8f143ea2c..ee3cf3bd7 100644 --- a/packages/e2e/src/helper/createTestEnv.ts +++ b/packages/e2e/src/helper/createTestEnv.ts @@ -27,7 +27,7 @@ export const CONFIG = { }, }, LIVE: { - nativeFundingAmount: '0.2', + nativeFundingAmount: '0.5', ledgerDepositAmount: '10', sponsorshipLimits: { totalMaxPriceInWei: '50000000000000000', @@ -35,7 +35,7 @@ export const CONFIG = { }, }, MAINNET: { - nativeFundingAmount: '0.2', + nativeFundingAmount: '0.5', ledgerDepositAmount: '0.01', sponsorshipLimits: { totalMaxPriceInWei: '10000000000000000', diff --git a/packages/e2e/src/init.ts b/packages/e2e/src/init.ts index 7cb6f970f..80409e400 100644 --- a/packages/e2e/src/init.ts +++ b/packages/e2e/src/init.ts @@ -40,10 +40,10 @@ const LogLevelSchema = z.enum(['silent', 'info', 'debug']); type LogLevel = z.infer; // Configurations -const LIVE_NETWORK_FUNDING_AMOUNT = '0.2'; +const LIVE_NETWORK_FUNDING_AMOUNT = '0.5'; const LOCAL_NETWORK_FUNDING_AMOUNT = '1'; const LIVE_NETWORK_LEDGER_DEPOSIT_AMOUNT = '1'; -const MAINNET_NETWORK_FUNDING_AMOUNT = '0.2'; +const MAINNET_NETWORK_FUNDING_AMOUNT = '0.5'; const MAINNET_LEDGER_DEPOSIT_AMOUNT = '0.01'; const EVE_VALIDATION_IPFS_CID = @@ -152,7 +152,7 @@ async function initInternal( ): module is NagaLocalModule => !!module && typeof (module as { withLocalContext?: unknown }).withLocalContext === - 'function'; + 'function'; if (supportsLocalContext(networkModule)) { const localContextName = process.env['NETWORK']; @@ -193,8 +193,8 @@ async function initInternal( const fundingAmount = isLocal ? LOCAL_NETWORK_FUNDING_AMOUNT : isMainnet - ? MAINNET_NETWORK_FUNDING_AMOUNT - : LIVE_NETWORK_FUNDING_AMOUNT; + ? MAINNET_NETWORK_FUNDING_AMOUNT + : LIVE_NETWORK_FUNDING_AMOUNT; const ledgerDepositAmount = isMainnet ? MAINNET_LEDGER_DEPOSIT_AMOUNT : LIVE_NETWORK_LEDGER_DEPOSIT_AMOUNT; From 771836c934daff4fa3e1e8ec5efc42c005e47030 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 18 Dec 2025 16:27:23 -1000 Subject: [PATCH 15/17] chore: lint --- packages/e2e/src/init.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/e2e/src/init.ts b/packages/e2e/src/init.ts index 80409e400..8bae7b3f5 100644 --- a/packages/e2e/src/init.ts +++ b/packages/e2e/src/init.ts @@ -152,7 +152,7 @@ async function initInternal( ): module is NagaLocalModule => !!module && typeof (module as { withLocalContext?: unknown }).withLocalContext === - 'function'; + 'function'; if (supportsLocalContext(networkModule)) { const localContextName = process.env['NETWORK']; @@ -193,8 +193,8 @@ async function initInternal( const fundingAmount = isLocal ? LOCAL_NETWORK_FUNDING_AMOUNT : isMainnet - ? MAINNET_NETWORK_FUNDING_AMOUNT - : LIVE_NETWORK_FUNDING_AMOUNT; + ? MAINNET_NETWORK_FUNDING_AMOUNT + : LIVE_NETWORK_FUNDING_AMOUNT; const ledgerDepositAmount = isMainnet ? MAINNET_LEDGER_DEPOSIT_AMOUNT : LIVE_NETWORK_LEDGER_DEPOSIT_AMOUNT; From bf7e29faab4972a038d14cdbd9906f431b22dc6c Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 18 Dec 2025 16:58:18 -1000 Subject: [PATCH 16/17] chore: debugging fund amount --- packages/e2e/src/helper/createTestEnv.ts | 6 +++--- packages/e2e/src/init.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/e2e/src/helper/createTestEnv.ts b/packages/e2e/src/helper/createTestEnv.ts index ee3cf3bd7..deb27353d 100644 --- a/packages/e2e/src/helper/createTestEnv.ts +++ b/packages/e2e/src/helper/createTestEnv.ts @@ -27,15 +27,15 @@ export const CONFIG = { }, }, LIVE: { - nativeFundingAmount: '0.5', - ledgerDepositAmount: '10', + nativeFundingAmount: '0.8', + ledgerDepositAmount: '12', sponsorshipLimits: { totalMaxPriceInWei: '50000000000000000', userMaxPrice: 50000000000000000n, }, }, MAINNET: { - nativeFundingAmount: '0.5', + nativeFundingAmount: '0.01', ledgerDepositAmount: '0.01', sponsorshipLimits: { totalMaxPriceInWei: '10000000000000000', diff --git a/packages/e2e/src/init.ts b/packages/e2e/src/init.ts index 8bae7b3f5..260648fa6 100644 --- a/packages/e2e/src/init.ts +++ b/packages/e2e/src/init.ts @@ -40,10 +40,10 @@ const LogLevelSchema = z.enum(['silent', 'info', 'debug']); type LogLevel = z.infer; // Configurations -const LIVE_NETWORK_FUNDING_AMOUNT = '0.5'; +const LIVE_NETWORK_FUNDING_AMOUNT = '0.2'; const LOCAL_NETWORK_FUNDING_AMOUNT = '1'; -const LIVE_NETWORK_LEDGER_DEPOSIT_AMOUNT = '1'; -const MAINNET_NETWORK_FUNDING_AMOUNT = '0.5'; +const LIVE_NETWORK_LEDGER_DEPOSIT_AMOUNT = '1.2'; +const MAINNET_NETWORK_FUNDING_AMOUNT = '0.01'; const MAINNET_LEDGER_DEPOSIT_AMOUNT = '0.01'; const EVE_VALIDATION_IPFS_CID = From 70a1916fb0aedfa597ba791f969f6255eea54bb0 Mon Sep 17 00:00:00 2001 From: spacesailor24 Date: Fri, 19 Dec 2025 10:09:06 -1000 Subject: [PATCH 17/17] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: spacesailor24 --- .../executeJs/paymentBenchmarks/litActions/crossChainSwap.ts | 2 +- .../executeJs/paymentBenchmarks/litActions/oracleOperation.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts index f07c43d8f..ee86d48c6 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/crossChainSwap.ts @@ -16,7 +16,7 @@ async function crossChainSwap() { sourceToken: 'ETH', destToken: 'BTC', amountIn: '1.0', // 1 ETH - userAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', // Example address + userAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0', // Example address slippageTolerance: 0.5, // 0.5% }; diff --git a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts index 54fcb4eab..f60c51052 100644 --- a/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts +++ b/packages/e2e/src/test-helpers/executeJs/paymentBenchmarks/litActions/oracleOperation.ts @@ -9,7 +9,7 @@ declare const ethers: any; async function oracleOperation() { // Helper function to calculate median const median = (arr: number[]) => { - const arrSorted = arr.sort((a, b) => a - b); + const arrSorted = [...arr].sort((a, b) => a - b); return arrSorted.length % 2 === 0 ? (arrSorted[arrSorted.length / 2 - 1] + arrSorted[arrSorted.length / 2]) /