diff --git a/packages/apps/registry-backend/src/lib/getAgentFunds.ts b/packages/apps/registry-backend/src/lib/getAgentFunds.ts index 23f0a3fd0..fb398fe3c 100644 --- a/packages/apps/registry-backend/src/lib/getAgentFunds.ts +++ b/packages/apps/registry-backend/src/lib/getAgentFunds.ts @@ -58,4 +58,4 @@ export async function getAgentFunds( tokens: data.data.tokens, pageKey: data.data.pageKey, }; -} \ No newline at end of file +} diff --git a/packages/libs/e2e-test-utils/.env.test.example b/packages/libs/e2e-test-utils/.env.example similarity index 100% rename from packages/libs/e2e-test-utils/.env.test.example rename to packages/libs/e2e-test-utils/.env.example diff --git a/packages/libs/e2e-test-utils/eslint.config.js b/packages/libs/e2e-test-utils/eslint.config.js index 295a0d9f5..f4b6083cc 100644 --- a/packages/libs/e2e-test-utils/eslint.config.js +++ b/packages/libs/e2e-test-utils/eslint.config.js @@ -7,6 +7,20 @@ module.exports = [ files: ['**/*.ts', '**/*.tsx'], rules: { '@typescript-eslint/no-floating-promises': 'off', + '@nx/dependency-checks': [ + 'error', + { + buildTargets: ['build'], + checkVersionMismatches: true, + ignoredFiles: [ + '{projectRoot}/eslint.config.{js,cjs,mjs}', + '{projectRoot}/jest.config.{js,cjs,mjs,ts}', + '{projectRoot}/vite.config.*', + '{projectRoot}/esbuild.config.{js,cjs,mjs}', + ], + ignoredDependencies: ['@lit-protocol/contracts-sdk'], + }, + ], }, }, ]; diff --git a/packages/libs/e2e-test-utils/package.json b/packages/libs/e2e-test-utils/package.json index ab7434cd7..090492dd6 100644 --- a/packages/libs/e2e-test-utils/package.json +++ b/packages/libs/e2e-test-utils/package.json @@ -1,17 +1,12 @@ { "name": "@lit-protocol/vincent-e2e-test-utils", - "version": "4.0.0", + "version": "4.0.1-alpha.0", "publishConfig": { "access": "public" }, "dependencies": { - "@lit-protocol/vincent-app-sdk": "workspace:*", "@lit-protocol/contracts-sdk": "^7.2.3", - "@lit-protocol/pkp-ethers": "^7.3.1", "@lit-protocol/vincent-contracts-sdk": "workspace:*", - "@zerodev/ecdsa-validator": "^5.4.9", - "@zerodev/permissions": "^5.6.2", - "@zerodev/sdk": "^5.5.3", "ethers": "^5.7.2", "tslib": "^2.8.1", "viem": "^2.38.3" @@ -29,7 +24,6 @@ } }, "devDependencies": { - "@lit-protocol/vincent-contracts-sdk": "workspace:*", "@types/semver": "^7.7.0", "chokidar-cli": "^3.0.0", "dotenv-cli": "^7.4.2", diff --git a/packages/libs/e2e-test-utils/src/index.ts b/packages/libs/e2e-test-utils/src/index.ts index de431d804..25ea5150c 100644 --- a/packages/libs/e2e-test-utils/src/index.ts +++ b/packages/libs/e2e-test-utils/src/index.ts @@ -1,8 +1,3 @@ -export { - deploySmartAccount, - ensureWalletHasTokens, - getEnv, - setupVincentDevelopmentEnvironment, -} from './setup-dev-env'; +export { ensureWalletHasTokens, getEnv, setupVincentDevelopmentEnvironment } from './setup-dev-env'; -export type { SetupConfig, SmartAccountInfo, VincentDevEnvironment } from './setup-dev-env'; +export type { SetupConfig, VincentDevEnvironment } from './setup-dev-env'; diff --git a/packages/libs/e2e-test-utils/src/setup-dev-env/index.ts b/packages/libs/e2e-test-utils/src/setup-dev-env/index.ts index 47c6c182e..ab1bd58ff 100644 --- a/packages/libs/e2e-test-utils/src/setup-dev-env/index.ts +++ b/packages/libs/e2e-test-utils/src/setup-dev-env/index.ts @@ -1,7 +1,5 @@ export { setupVincentDevelopmentEnvironment } from './setupVincentDevEnv'; export { getEnv } from './getEnv'; -export { deploySmartAccount } from './smart-account/deploySmartAccount'; export { ensureWalletHasTokens } from './wallets/ensureWalletHasTokens'; export type { SetupConfig, VincentDevEnvironment } from './setupVincentDevEnv'; -export type { SmartAccountInfo } from './smart-account/deploySmartAccount'; diff --git a/packages/libs/e2e-test-utils/src/setup-dev-env/smart-account/createPermissionApproval.ts b/packages/libs/e2e-test-utils/src/setup-dev-env/smart-account/createPermissionApproval.ts deleted file mode 100644 index e70ca12ab..000000000 --- a/packages/libs/e2e-test-utils/src/setup-dev-env/smart-account/createPermissionApproval.ts +++ /dev/null @@ -1,77 +0,0 @@ -import type { Address, Chain } from 'viem'; - -import { signerToEcdsaValidator } from '@zerodev/ecdsa-validator'; -import { serializePermissionAccount, toPermissionValidator } from '@zerodev/permissions'; -import { toSudoPolicy } from '@zerodev/permissions/policies'; -import { toECDSASigner } from '@zerodev/permissions/signers'; -import { addressToEmptyAccount, createKernelAccount } from '@zerodev/sdk'; -import { getEntryPoint, KERNEL_V3_3 } from '@zerodev/sdk/constants'; -import { createPublicClient, http } from 'viem'; -import { privateKeyToAccount } from 'viem/accounts'; - -/** - * Creates a serialized permission approval that allows a session key (PKP) to act on behalf of the smart account. - * - * This follows the ZeroDev pattern from transaction-automation.ts: - * 1. Owner creates an account with BOTH validators (EOA sudo + session key permission) - * 2. Serializes the permission account - * 3. Session key can later deserialize and use it to sign transactions - * - * The serialized approval contains: - * - Smart account configuration (sudo validator = EOA) - * - Permission validator configuration (session key = PKP with sudo policy) - * - All necessary data for the session key to reconstruct the account - * - * @param params Configuration for creating the permission approval - * @returns Serialized permission approval string that can be deserialized by the session key - */ -export async function createPermissionApproval({ - userEoaPrivateKey, - sessionKeyAddress, - accountIndexHash, - targetChain, - targetChainRpcUrl, -}: { - userEoaPrivateKey: `0x${string}`; - sessionKeyAddress: Address; - accountIndexHash: string; - targetChain: Chain; - targetChainRpcUrl: string; -}): Promise { - const publicClient = createPublicClient({ - chain: targetChain, - transport: http(targetChainRpcUrl), - }); - - const userEoaAccount = privateKeyToAccount(userEoaPrivateKey); - - const ecdsaValidator = await signerToEcdsaValidator(publicClient, { - entryPoint: getEntryPoint('0.7'), - signer: userEoaAccount, - kernelVersion: KERNEL_V3_3, - }); - - const emptySessionKeyAccount = addressToEmptyAccount(sessionKeyAddress); - const emptySessionKeySigner = await toECDSASigner({ - signer: emptySessionKeyAccount, - }); - - const permissionPlugin = await toPermissionValidator(publicClient, { - entryPoint: getEntryPoint('0.7'), - signer: emptySessionKeySigner, - policies: [toSudoPolicy({})], - kernelVersion: KERNEL_V3_3, - }); - - const sessionKeyAccount = await createKernelAccount(publicClient, { - entryPoint: getEntryPoint('0.7'), - plugins: { - sudo: ecdsaValidator, - regular: permissionPlugin, - }, - kernelVersion: KERNEL_V3_3, - index: BigInt(accountIndexHash), - }); - - return await serializePermissionAccount(sessionKeyAccount); -} diff --git a/packages/libs/e2e-test-utils/src/setup-dev-env/smart-account/deploySmartAccount.ts b/packages/libs/e2e-test-utils/src/setup-dev-env/smart-account/deploySmartAccount.ts deleted file mode 100644 index cae2af0c0..000000000 --- a/packages/libs/e2e-test-utils/src/setup-dev-env/smart-account/deploySmartAccount.ts +++ /dev/null @@ -1,169 +0,0 @@ -import type { Address, Chain, Hex } from 'viem'; - -import { signerToEcdsaValidator } from '@zerodev/ecdsa-validator'; -import { createKernelAccount, createKernelAccountClient } from '@zerodev/sdk'; -import { getEntryPoint, KERNEL_V3_3 } from '@zerodev/sdk/constants'; -import { createPublicClient, createWalletClient, formatEther, http } from 'viem'; -import { privateKeyToAccount } from 'viem/accounts'; - -import { ensureWalletHasTokens } from '../wallets/ensureWalletHasTokens'; - -export interface SmartAccountInfo { - smartAccountAddress: Address; - deploymentTxHash?: Hex; -} - -export async function deploySmartAccount({ - userEoaPrivateKey, - accountIndexHash, - targetChain, - targetChainRpcUrl, - zerodevProjectId, - funderPrivateKey, - fundAmountBeforeDeployment, -}: { - userEoaPrivateKey: `0x${string}`; - accountIndexHash: string; - targetChain: Chain; - targetChainRpcUrl: string; - zerodevProjectId: string; - funderPrivateKey: `0x${string}`; - fundAmountBeforeDeployment?: bigint; -}): Promise { - console.log(`=== Deploying Smart Account to ${targetChain.name} ===`); - - const publicClient = createPublicClient({ - chain: targetChain, - transport: http(targetChainRpcUrl), - }); - - const userEoaWalletClient = createWalletClient({ - account: privateKeyToAccount(userEoaPrivateKey), - chain: targetChain, - transport: http(targetChainRpcUrl), - }); - - const funderWalletClient = createWalletClient({ - account: privateKeyToAccount(funderPrivateKey), - chain: targetChain, - transport: http(targetChainRpcUrl), - }); - - const userEoaEcdsaValidator = await signerToEcdsaValidator(publicClient, { - entryPoint: getEntryPoint('0.7'), - signer: userEoaWalletClient, - kernelVersion: KERNEL_V3_3, - }); - - const userEoaKernelAccount = await createKernelAccount(publicClient, { - entryPoint: getEntryPoint('0.7'), - plugins: { - sudo: userEoaEcdsaValidator, - }, - kernelVersion: KERNEL_V3_3, - index: BigInt(accountIndexHash), - }); - - const zerodevRpcUrl = `https://rpc.zerodev.app/api/v3/${zerodevProjectId}/chain/${targetChain.id}`; - const kernelClient = createKernelAccountClient({ - account: userEoaKernelAccount, - chain: targetChain, - bundlerTransport: http(zerodevRpcUrl), - client: publicClient, - }); - - // Check if smart account is already deployed on the target chain - const existingCode = await publicClient.getCode({ - address: userEoaKernelAccount.address, - }); - const isAlreadyDeployed = existingCode && existingCode !== '0x'; - - if (isAlreadyDeployed) { - console.log(`Smart account already deployed on ${targetChain.name}`); - console.table({ - Chain: `${targetChain.name} (${targetChain.id})`, - 'Smart Account Address': userEoaKernelAccount.address, - Status: 'Already Deployed', - }); - } - - // Step 2: Fund the smart account (if fundAmountBeforeDeployment is provided) - if (fundAmountBeforeDeployment !== undefined) { - console.log('Funding smart account...'); - const { currentBalance, fundingTxHash } = await ensureWalletHasTokens({ - address: userEoaKernelAccount.address, - funderWalletClient, - publicClient, - minAmount: fundAmountBeforeDeployment, - }); - - console.table({ - 'Smart Account Address': userEoaKernelAccount.address, - Balance: formatEther(currentBalance), - 'Funding Tx Hash': fundingTxHash, - }); - - if (fundingTxHash) { - console.log('Waiting for funding confirmation...'); - await publicClient.waitForTransactionReceipt({ - hash: fundingTxHash as `0x${string}`, - confirmations: 2, - }); - } - } else { - console.log('Skipping funding step (fundAmountBeforeDeployment not provided)'); - } - - // Step 3: Deploy the smart account (only if not already deployed) - let deploymentTxHash: `0x${string}` | undefined; - - if (!isAlreadyDeployed) { - console.log('Deploying smart account...'); - - const userOpHash = await kernelClient.sendUserOperation({ - callData: await userEoaKernelAccount.encodeCalls([ - { - to: '0x0000000000000000000000000000000000000000', - value: 0n, - data: '0x', - }, - ]), - }); - console.log(`Deployment UserOp Hash: ${userOpHash}`); - - // Wait for the UserOperation to be included in a block - const receipt = await kernelClient.waitForUserOperationReceipt({ - hash: userOpHash, - }); - deploymentTxHash = receipt.receipt.transactionHash; - console.log(`Deployment Tx Hash: ${deploymentTxHash}`); - - await publicClient.waitForTransactionReceipt({ - hash: deploymentTxHash as `0x${string}`, - confirmations: 2, - }); - - // Verify deployment - const deployedCode = await publicClient.getCode({ - address: userEoaKernelAccount.address, - }); - - if (!deployedCode || deployedCode === '0x') { - throw new Error( - `Smart account deployment failed on ${targetChain.name}, code is still empty (0x)`, - ); - } - - console.log(`Smart account deployed successfully`); - console.table({ - Chain: `${targetChain.name} (${targetChain.id})`, - 'Smart Account Address': userEoaKernelAccount.address, - 'Deployment Tx Hash': deploymentTxHash, - }); - } - - return { - smartAccountAddress: userEoaKernelAccount.address, - deploymentTxHash, - }; -} diff --git a/packages/libs/e2e-test-utils/src/setup-dev-env/smart-account/deriveSmartAccountAddress.ts b/packages/libs/e2e-test-utils/src/setup-dev-env/smart-account/deriveSmartAccountAddress.ts deleted file mode 100644 index 116765fd9..000000000 --- a/packages/libs/e2e-test-utils/src/setup-dev-env/smart-account/deriveSmartAccountAddress.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Address } from 'viem'; - -import { getKernelAddressFromECDSA } from '@zerodev/ecdsa-validator'; -import { KERNEL_V3_1, getEntryPoint } from '@zerodev/sdk/constants'; - -export async function deriveSmartAccountAddress( - eoaAddress: Address, - accountIndexHash: string, - publicClient: any, -): Promise
{ - const agentAddress = await getKernelAddressFromECDSA({ - entryPoint: getEntryPoint('0.7'), - kernelVersion: KERNEL_V3_1, - eoaAddress, - index: BigInt(accountIndexHash), - publicClient: publicClient as any, - }); - - return agentAddress as Address; -} diff --git a/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/completeAppInstallation.ts b/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/completeAppInstallation.ts index b12560644..9ba5f27ad 100644 --- a/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/completeAppInstallation.ts +++ b/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/completeAppInstallation.ts @@ -56,7 +56,6 @@ export async function completeAppInstallation({ body: JSON.stringify({ userControllerAddress: viemAccount.address, agentSignerAddress, - appId, appInstallation: { typedDataSignature: appInstallationSignature, dataToSign: appInstallationDataToSign, diff --git a/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/generateAppManagerJwt.ts b/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/generateAppManagerJwt.ts deleted file mode 100644 index c3793138f..000000000 --- a/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/generateAppManagerJwt.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Wallet } from 'ethers'; - -import type { PKPEthersWallet } from '@lit-protocol/pkp-ethers'; - -import { createPlatformUserJWT } from '@lit-protocol/vincent-app-sdk/jwt'; - -export async function generateAppManagerJwt({ - appManagerPrivateKey, -}: { - appManagerPrivateKey: `0x${string}`; -}): Promise { - const wallet = new Wallet(appManagerPrivateKey); - const address = await wallet.getAddress(); - - const jwt = await createPlatformUserJWT({ - pkpWallet: wallet as unknown as PKPEthersWallet, - pkpInfo: { - tokenId: '0', // Not used for app manager auth - publicKey: wallet.publicKey, - ethAddress: address, - }, - payload: { - name: 'Vincent App Manager', - }, - expiresInMinutes: 2, - audience: 'registry.heyvincent.ai', - authentication: { - type: 'wallet', - value: address, - }, - }); - - return jwt; -} diff --git a/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/generateSiweAuth.ts b/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/generateSiweAuth.ts new file mode 100644 index 000000000..59d8b8c0c --- /dev/null +++ b/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/generateSiweAuth.ts @@ -0,0 +1,156 @@ +import crypto from 'crypto'; + +import { Wallet } from 'ethers'; +import { getAddress } from 'viem'; + +/** + * Generate a secure random nonce for SIWE + */ +function generateNonce(): string { + // Generate 16 random bytes and convert to hex string + const array = new Uint8Array(16); + crypto.randomFillSync(array); + return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join(''); +} + +/** + * Creates a SIWE message following the EIP-4361 spec + */ +function createSiweMessage(params: { + domain: string; + address: string; + uri: string; + nonce: string; + issuedAt: string; + expirationTime?: string; + statement?: string; + chainId?: number; + version?: string; +}): string { + const { + domain, + address, + uri, + nonce, + issuedAt, + expirationTime, + statement = 'Sign in with Ethereum to authenticate with Vincent Registry API', + chainId = 85452, + version = '1', + } = params; + + const lines = [ + `${domain} wants you to sign in with your Ethereum account:`, + address, + '', + statement, + '', + `URI: ${uri}`, + `Version: ${version}`, + `Chain ID: ${chainId}`, + `Nonce: ${nonce}`, + `Issued At: ${issuedAt}`, + ]; + + if (expirationTime) { + lines.push(`Expiration Time: ${expirationTime}`); + } + + return lines.join('\n'); +} + +/** + * Infers the SIWE domain and URI from the Vincent API URL + * Production: url='https://api.heyvincent.ai' -> domain='vincent-dashboard-20.vercel.app', uri='https://api.heyvincent.ai' + * Development: url='http://localhost:3000' -> domain='localhost:3000', uri='http://localhost:3000' + */ +function inferDomainAndUri(apiUrl: string): { domain: string; uri: string } { + const urlObj = new URL(apiUrl); + + // Check if it's production API + if (urlObj.hostname === 'api.heyvincent.ai') { + return { + domain: 'vincent-dashboard-20.vercel.app', + uri: apiUrl, + }; + } + + // For localhost or other environments, use the URL's host (including port) + return { + domain: urlObj.host, // includes port if present + uri: apiUrl, + }; +} + +/** + * Generates a SIWE (Sign-In with Ethereum) authentication header for Vincent Registry API + * @param appManagerPrivateKey - The private key of the app manager + * @param vincentApiUrl - The Vincent Registry API URL (e.g., 'http://localhost:3000' or 'https://api.heyvincent.ai') + * @param domain - Optional override for the domain (if not provided, will be inferred from vincentApiUrl) + * @returns The Authorization header value in the format "SIWE " + */ +export async function generateSiweAuth({ + appManagerPrivateKey, + vincentApiUrl, + domain: domainOverride, +}: { + appManagerPrivateKey: `0x${string}`; + vincentApiUrl?: string; + domain?: string; +}): Promise { + const wallet = new Wallet(appManagerPrivateKey); + + // Get checksummed address (EIP-55 required by SIWE) + const address = await wallet.getAddress(); + const checksummedAddress = getAddress(address); + + // Infer domain and URI from the API URL, or use override + let domain: string; + let uri: string; + + if (domainOverride) { + // If domain is explicitly provided, use it + domain = domainOverride; + // Infer URI from domain if not using vincentApiUrl + uri = + vincentApiUrl || (domain.includes('localhost') ? `http://${domain}` : `https://${domain}`); + } else if (vincentApiUrl) { + // Infer both domain and URI from the API URL + const inferred = inferDomainAndUri(vincentApiUrl); + domain = inferred.domain; + uri = inferred.uri; + } else { + // Fallback to localhost defaults + domain = 'localhost:3000'; + uri = 'http://localhost:3000'; + } + + const timestamp = Date.now(); + const issuedAt = new Date(timestamp).toISOString(); + const expirationTime = new Date(timestamp + 7 * 24 * 60 * 60 * 1000).toISOString(); // 7 days + + // Create the SIWE message + const message = createSiweMessage({ + domain, + address: checksummedAddress, + uri, + nonce: generateNonce(), + issuedAt, + expirationTime, + }); + + // Request signature from wallet + const signature = await wallet.signMessage(message); + + // Create the payload + const payload = JSON.stringify({ + message, + signature, + }); + + // Encode as base64 + const base64Payload = Buffer.from(payload, 'utf-8').toString('base64'); + + // Return the Authorization header value + return `SIWE ${base64Payload}`; +} diff --git a/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/registerApp.ts b/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/registerApp.ts index 7834a8a3e..c4230ba09 100644 --- a/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/registerApp.ts +++ b/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/registerApp.ts @@ -1,27 +1,31 @@ import type { AppMetadata } from '../setupVincentDevEnv'; -import { generateAppManagerJwt } from './generateAppManagerJwt'; +import { generateSiweAuth } from './generateSiweAuth'; export async function registerApp({ vincentApiUrl, appManagerPrivateKey, appId, appMetadata, + domain, }: { vincentApiUrl: string; appManagerPrivateKey: `0x${string}`; appId: number; appMetadata: AppMetadata; + domain?: string; }): Promise { - const jwtToken = await generateAppManagerJwt({ + const authHeader = await generateSiweAuth({ appManagerPrivateKey, + vincentApiUrl, + domain, }); const response = await fetch(`${vincentApiUrl}/app`, { method: 'POST', headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${jwtToken}`, + Authorization: authHeader, }, body: JSON.stringify({ appId, diff --git a/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/registerAppVersion.ts b/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/registerAppVersion.ts index f1efa8606..adf46807b 100644 --- a/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/registerAppVersion.ts +++ b/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/registerAppVersion.ts @@ -1,25 +1,29 @@ -import { generateAppManagerJwt } from './generateAppManagerJwt'; +import { generateSiweAuth } from './generateSiweAuth'; export async function registerAppVersion({ vincentApiUrl, appManagerPrivateKey, appId, whatChanged, + domain, }: { vincentApiUrl: string; appManagerPrivateKey: `0x${string}`; appId: number; whatChanged: string; + domain?: string; }): Promise<{ newAppVersion: number }> { - const jwtToken = await generateAppManagerJwt({ + const authHeader = await generateSiweAuth({ appManagerPrivateKey, + vincentApiUrl, + domain, }); const response = await fetch(`${vincentApiUrl}/app/${appId}/version`, { method: 'POST', headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${jwtToken}`, + Authorization: authHeader, }, body: JSON.stringify({ changes: whatChanged, diff --git a/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/setActiveAppVersion.ts b/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/setActiveAppVersion.ts index 7c0c1428a..d9c39aabe 100644 --- a/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/setActiveAppVersion.ts +++ b/packages/libs/e2e-test-utils/src/setup-dev-env/vincent-registry-api/setActiveAppVersion.ts @@ -1,27 +1,31 @@ -import { generateAppManagerJwt } from './generateAppManagerJwt'; +import { generateSiweAuth } from './generateSiweAuth'; export async function setActiveVersion({ vincentApiUrl, appManagerPrivateKey, appId, activeVersion, + domain, }: { vincentApiUrl: string; appManagerPrivateKey: `0x${string}`; appId: number; activeVersion: number; + domain?: string; }): Promise { console.log('=== Setting active version with Vincent API ==='); - const jwtToken = await generateAppManagerJwt({ + const authHeader = await generateSiweAuth({ appManagerPrivateKey, + vincentApiUrl, + domain, }); const response = await fetch(`${vincentApiUrl}/app/${appId}/setActiveVersion`, { method: 'POST', headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${jwtToken}`, + Authorization: authHeader, }, body: JSON.stringify({ activeVersion, diff --git a/packages/libs/e2e-test-utils/test/setupVincentDevEnv.spec.ts b/packages/libs/e2e-test-utils/test/setupVincentDevEnv.spec.ts index dd7246714..90a122406 100644 --- a/packages/libs/e2e-test-utils/test/setupVincentDevEnv.spec.ts +++ b/packages/libs/e2e-test-utils/test/setupVincentDevEnv.spec.ts @@ -1,5 +1,5 @@ import { ethers } from 'ethers'; -import { baseSepolia } from 'viem/chains'; +import { base, baseSepolia } from 'viem/chains'; import { getClient } from '@lit-protocol/vincent-contracts-sdk'; @@ -172,19 +172,19 @@ describe('Vincent Development Environment Setup', () => { describe('PKP and Smart Account', () => { it('should have PKP signer address from registry API', () => { - expect(env.agentSmartAccount.agentSignerAddress).toBeDefined(); - expect(env.agentSmartAccount.agentSignerAddress).toMatch(/^0x[a-fA-F0-9]{40}$/); + expect(env.agentSmartAccount!.agentSignerAddress).toBeDefined(); + expect(env.agentSmartAccount!.agentSignerAddress).toMatch(/^0x[a-fA-F0-9]{40}$/); }); it('should have smart account address', () => { - expect(env.agentSmartAccount.address).toBeDefined(); - expect(env.agentSmartAccount.address).toMatch(/^0x[a-fA-F0-9]{40}$/); + expect(env.agentSmartAccount!.address).toBeDefined(); + expect(env.agentSmartAccount!.address).toMatch(/^0x[a-fA-F0-9]{40}$/); }); it('should have smart account deployed on-chain', async () => { // Smart account is deployed on the smart account chain, not the Vincent Registry chain const provider = new ethers.providers.JsonRpcProvider(env.smartAccountChainRpcUrl); - const code = await provider.getCode(env.agentSmartAccount.address); + const code = await provider.getCode(env.agentSmartAccount!.address); expect(code).toBeDefined(); expect(code).not.toBe('0x'); @@ -193,24 +193,31 @@ describe('Vincent Development Environment Setup', () => { it('should have deployment transaction hash (or be already deployed)', () => { // deploymentTxHash might be undefined if already installed - if (env.agentSmartAccount.deploymentTxHash) { - expect(env.agentSmartAccount.deploymentTxHash).toMatch(/^0x[a-fA-F0-9]{64}$/); + if (env.agentSmartAccount!.deploymentTxHash) { + expect(env.agentSmartAccount!.deploymentTxHash).toMatch(/^0x[a-fA-F0-9]{64}$/); } }); it('should have serialized permission account (or be already installed)', () => { // serializedPermissionAccount might be undefined if already installed - if (env.agentSmartAccount.serializedPermissionAccount) { - expect(env.agentSmartAccount.serializedPermissionAccount).toBeTruthy(); - expect(env.agentSmartAccount.serializedPermissionAccount.length).toBeGreaterThan(0); - expect(() => JSON.parse(env.agentSmartAccount.serializedPermissionAccount!)).not.toThrow(); + if (env.agentSmartAccount!.serializedPermissionAccount) { + expect(env.agentSmartAccount!.serializedPermissionAccount).toBeTruthy(); + expect(env.agentSmartAccount!.serializedPermissionAccount.length).toBeGreaterThan(0); + expect(() => + Buffer.from(env.agentSmartAccount!.serializedPermissionAccount!, 'base64'), + ).not.toThrow(); + const decoded = Buffer.from( + env.agentSmartAccount!.serializedPermissionAccount!, + 'base64', + ).toString('utf-8'); + expect(() => JSON.parse(decoded)).not.toThrow(); } }); it('should have permit app version transaction hash (or be already installed)', () => { // permitAppVersionTxHash might be undefined if already installed - if (env.agentSmartAccount.permitAppVersionTxHash) { - expect(env.agentSmartAccount.permitAppVersionTxHash).toMatch(/^0x[a-fA-F0-9]{64}$/); + if (env.agentSmartAccount!.permitAppVersionTxHash) { + expect(env.agentSmartAccount!.permitAppVersionTxHash).toMatch(/^0x[a-fA-F0-9]{64}$/); } }); @@ -220,7 +227,7 @@ describe('Vincent Development Environment Setup', () => { const contractClient = getClient({ signer: wallet }); const userAddress = await contractClient.getUserAddressForAgent({ - agentAddress: env.agentSmartAccount.address as `0x${string}`, + agentAddress: env.agentSmartAccount!.address as `0x${string}`, }); expect(userAddress).toBeDefined(); @@ -336,12 +343,12 @@ describe('Vincent Development Environment Setup', () => { describe('Integration Checks', () => { it('should have PKP and smart account addresses that are different', () => { - expect(env.agentSmartAccount.agentSignerAddress).not.toBe(env.agentSmartAccount.address); - expect(env.agentSmartAccount.agentSignerAddress).not.toBe(env.accounts.userEoa.address); + expect(env.agentSmartAccount!.agentSignerAddress).not.toBe(env.agentSmartAccount!.address); + expect(env.agentSmartAccount!.agentSignerAddress).not.toBe(env.accounts.userEoa.address); }); it('should have smart account different from user EOA', () => { - expect(env.agentSmartAccount.address.toLowerCase()).not.toBe( + expect(env.agentSmartAccount!.address.toLowerCase()).not.toBe( env.accounts.userEoa.address.toLowerCase(), ); }); @@ -355,7 +362,7 @@ describe('Vincent Development Environment Setup', () => { expect(env.accounts).toBeDefined(); expect(env.ethersWallets).toBeDefined(); expect(env.clients).toBeDefined(); - expect(env.agentSmartAccount).toBeDefined(); + expect(env.agentSmartAccount!).toBeDefined(); }); it('should have correct chain ID for Vincent Registry', () => { @@ -375,15 +382,15 @@ describe('Vincent Development Environment Setup', () => { 'App Manager': env.accounts.appManager.address, 'App Delegatee': env.accounts.appDelegatee.address, 'User EOA': env.accounts.userEoa.address, - 'Agent Signer Address': env.agentSmartAccount.agentSignerAddress, - 'Agent Smart Account Address': env.agentSmartAccount.address, + 'Agent Signer Address': env.agentSmartAccount!.agentSignerAddress, + 'Agent Smart Account Address': env.agentSmartAccount!.address, 'Smart Account Deployment Tx': - env.agentSmartAccount.deploymentTxHash || 'N/A (already installed)', - 'Serialized Permission Account': env.agentSmartAccount.serializedPermissionAccount - ? env.agentSmartAccount.serializedPermissionAccount.substring(0, 50) + '...' + env.agentSmartAccount!.deploymentTxHash || 'N/A (already installed)', + 'Serialized Permission Account': env.agentSmartAccount!.serializedPermissionAccount + ? env.agentSmartAccount!.serializedPermissionAccount.substring(0, 50) + '...' : 'N/A (already installed)', 'Permit App Version Tx': - env.agentSmartAccount.permitAppVersionTxHash || 'N/A (already installed)', + env.agentSmartAccount!.permitAppVersionTxHash || 'N/A (already installed)', 'Vincent Registry Chain': `${vincentRegistryChain.name} (${vincentRegistryChain.id})`, 'Smart Account Chain': `${smartAccountChain.name} (${smartAccountChain.id})`, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c8f458c2..badf9be2f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1491,24 +1491,9 @@ importers: '@lit-protocol/contracts-sdk': specifier: ^7.2.3 version: 7.3.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@lit-protocol/pkp-ethers': - specifier: ^7.3.1 - version: 7.3.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@lit-protocol/vincent-app-sdk': - specifier: workspace:* - version: link:../app-sdk '@lit-protocol/vincent-contracts-sdk': specifier: workspace:* version: link:../contracts-sdk - '@zerodev/ecdsa-validator': - specifier: ^5.4.9 - version: 5.4.9(@zerodev/sdk@5.5.7(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13)))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@zerodev/permissions': - specifier: ^5.6.2 - version: 5.6.3(@zerodev/sdk@5.5.7(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13)))(@zerodev/webauthn-key@5.5.0(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13)))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@zerodev/sdk': - specifier: ^5.5.3 - version: 5.5.7(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13)) ethers: specifier: ^5.7.2 version: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -13383,10 +13368,12 @@ packages: tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me tar@7.5.2: resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==} engines: {node: '>=18'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me tcp-port-used@1.0.2: resolution: {integrity: sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==} @@ -23834,11 +23821,6 @@ snapshots: '@zerodev/sdk': 5.5.7(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64)) viem: 2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64) - '@zerodev/ecdsa-validator@5.4.9(@zerodev/sdk@5.5.7(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13)))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13))': - dependencies: - '@zerodev/sdk': 5.5.7(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13)) - viem: 2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13) - '@zerodev/ecdsa-validator@5.4.9(@zerodev/sdk@5.5.7(viem@2.43.5(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64)))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64))': dependencies: '@zerodev/sdk': 5.5.7(viem@2.43.5(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64)) @@ -23868,14 +23850,6 @@ snapshots: merkletreejs: 0.3.11 viem: 2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64) - '@zerodev/permissions@5.6.3(@zerodev/sdk@5.5.7(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13)))(@zerodev/webauthn-key@5.5.0(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13)))(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13))': - dependencies: - '@simplewebauthn/browser': 9.0.1 - '@zerodev/sdk': 5.5.7(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@zerodev/webauthn-key': 5.5.0(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13)) - merkletreejs: 0.3.11 - viem: 2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13) - '@zerodev/permissions@5.6.3(@zerodev/sdk@5.5.7(viem@2.43.5(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64)))(@zerodev/webauthn-key@5.5.0(viem@2.43.5(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64)))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64))': dependencies: '@simplewebauthn/browser': 9.0.1 @@ -23894,11 +23868,6 @@ snapshots: semver: 7.7.3 viem: 2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64) - '@zerodev/sdk@5.5.7(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13))': - dependencies: - semver: 7.7.3 - viem: 2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13) - '@zerodev/sdk@5.5.7(viem@2.43.5(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64))': dependencies: semver: 7.7.3 @@ -23918,13 +23887,6 @@ snapshots: '@simplewebauthn/types': 12.0.0 viem: 2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64) - '@zerodev/webauthn-key@5.5.0(viem@2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13))': - dependencies: - '@noble/curves': 1.9.7 - '@simplewebauthn/browser': 8.3.7 - '@simplewebauthn/types': 12.0.0 - viem: 2.41.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.13) - '@zerodev/webauthn-key@5.5.0(viem@2.43.5(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.64))': dependencies: '@noble/curves': 1.9.7