diff --git a/README.md b/README.md index 0875da7..76772fa 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This project demonstrates how to schedule and execute recurring DCA (Dollar-Cost - Node ^22.16.0 - pnpm ^10.7.0 - Docker or a local MongoDB instance -- A Vincent App with ERC20 approval and Uniswap swap abilities +- A Vincent App with Uniswap swap ability ## Monorepo Structure @@ -21,7 +21,6 @@ This codebase is composed of three main parts: - Express.js API server used by the frontend - Agenda-based job scheduler that runs DCA jobs - Integration with a Vincent App to execute swaps on behalf of users - - Vincent ERC20 Approval ability: authorizes Uniswap to spend user tokens - Vincent Uniswap Swap ability: executes the actual token swaps ## Packages @@ -45,14 +44,24 @@ To run this code and sign on behalf of your delegators, create your own Vincent 1. Go to the [Vincent Dashboard](https://dashboard.heyvincent.ai/) and log in as a builder. 2. Create a new app similar to [wBTC DCA](https://dashboard.heyvincent.ai/user/appId/9796398001/connect). -3. Add the ERC20 Approval ability. -4. Add the Uniswap Swap ability. -5. Publish the app. -6. Once users can connect to it, configure the backend with your App ID and the delegatee private key via environment variables. You can use the Deploy on Railway button below to deploy the entire app. -7. Once deployed, you'll need to update the `App User URL` and `Redirect URIs` to the URL deployed from Railway. +3. Add the Uniswap Swap ability. +4. Publish the app. +5. Once users can connect to it, configure the backend with your App ID and the delegatee private key via environment variables. You can use the Deploy on Railway button below to deploy the entire app. +6. Once deployed, you'll need to update the `App User URL` and `Redirect URIs` to the URL deployed from Railway. [![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/UY2g5I?referralCode=iNEMKY&utm_medium=integration&utm_source=template&utm_campaign=generic) +## Handling Multiple Vincent App Versions + +This repository is deployed as the [Vincent wBTC DCA App](https://dashboard.heyvincent.ai/explorer/appId/9796398001). The production app is a good example of how you might handle multiple versions of the same app, where some versions may rely on different abilities, or on different versions of the same ability. + +Note that the default configuration of this repository will use the latest version of the Uniswap Swap ability, but you can see an example of how to use different versions of the same ability in the [dca-backend](./packages/dca-backend/src/lib/agenda/jobs/executeDCASwap) package. + +If you want to modify the app version specific logic for your own app and enable it, you will need to: + +1. Modify the `getJobAPIVersionFromVincentAppVersion()` function in the [jobVersion.ts](./packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/jobVersion.ts) file appropriately for your app. +2. Set `ENABLE_APP_VERSIONING` env var to `true` to enable the per-app version logic. + ## Quick Start Install dependencies and build the packages (works for both local and production setups): diff --git a/package.json b/package.json index f93a2b1..babce66 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "devDependencies": { "@dotenvx/dotenvx": "^0.26.0", "@tsconfig/node20": "^20.1.5", - "@types/node": "^20.11.30", + "@types/node": "^22.16.0", "@types/verror": "^1.10.10", "@typescript-eslint/eslint-plugin": "^7.3.1", "@typescript-eslint/parser": "^7.3.1", diff --git a/packages/dca-backend/.env.example b/packages/dca-backend/.env.example index f3b67a7..2c927ba 100644 --- a/packages/dca-backend/.env.example +++ b/packages/dca-backend/.env.example @@ -13,4 +13,5 @@ SENTRY_DSN= SENTRY_PROJECT= SENTRY_ORG= VINCENT_APP_ID=0 -VINCENT_DELEGATEE_PRIVATE_KEY= \ No newline at end of file +VINCENT_DELEGATEE_PRIVATE_KEY= +ENABLE_APP_VERSIONING=false diff --git a/packages/dca-backend/package.json b/packages/dca-backend/package.json index 00027a4..3b09d5d 100644 --- a/packages/dca-backend/package.json +++ b/packages/dca-backend/package.json @@ -49,11 +49,12 @@ "@lit-protocol/contracts-sdk": "^7.3.0", "@lit-protocol/lit-node-client": "^7.3.0", "@lit-protocol/types": "^7.3.0", - "@lit-protocol/vincent-ability-erc20-approval": "3.1.0", - "@lit-protocol/vincent-ability-uniswap-swap": "5.0.0", - "@lit-protocol/vincent-app-sdk": "2.2.1", - "@lit-protocol/vincent-contracts-sdk": "^1.0.1", + "@lit-protocol/vincent-app-sdk": "2.2.3", + "@lit-protocol/vincent-contracts-sdk": "^2.0.0", "@lit-protocol/vincent-scaffold-sdk": "1.1.9-mma", + "@lit-protocol/vincent-ability-erc20-approval": "3.1.0", + "@lit-protocol/vincent-ability-uniswap-swap-v5": "npm:@lit-protocol/vincent-ability-uniswap-swap@5.0.0", + "@lit-protocol/vincent-ability-uniswap-swap-v8": "npm:@lit-protocol/vincent-ability-uniswap-swap@8.0.0", "@noble/secp256k1": "^2.2.3", "@sentry/cli": "^2.52.0", "@sentry/node": "^10.5.0", diff --git a/packages/dca-backend/src/lib/agenda/jobs/dcaSwapJobManager.ts b/packages/dca-backend/src/lib/agenda/jobs/dcaSwapJobManager.ts index 2963e76..11056cc 100644 --- a/packages/dca-backend/src/lib/agenda/jobs/dcaSwapJobManager.ts +++ b/packages/dca-backend/src/lib/agenda/jobs/dcaSwapJobManager.ts @@ -1,8 +1,9 @@ import consola from 'consola'; import { Types } from 'mongoose'; -import * as executeDCASwapJobDef from './executeDCASwap'; import { getAgenda } from '../agendaClient'; +import { jobName } from './executeDCASwap'; +import { JobParams, JobType } from './executeDCASwap/types'; interface FindSpecificScheduledJobParams { ethAddress: string; @@ -18,26 +19,22 @@ export async function listJobsByEthAddress({ ethAddress }: { ethAddress: string return (await agendaClient.jobs({ 'data.pkpInfo.ethAddress': ethAddress, - })) as executeDCASwapJobDef.JobType[]; + })) as JobType[]; } -export async function findJob( - params: FindSpecificScheduledJobParams -): Promise; -export async function findJob( - params: FindSpecificScheduledJobParams -): Promise; +export async function findJob(params: FindSpecificScheduledJobParams): Promise; +export async function findJob(params: FindSpecificScheduledJobParams): Promise; export async function findJob({ ethAddress, mustExist, scheduleId, -}: FindSpecificScheduledJobParams): Promise { +}: FindSpecificScheduledJobParams): Promise { const agendaClient = getAgenda(); const jobs = (await agendaClient.jobs({ _id: new Types.ObjectId(scheduleId), 'data.pkpInfo.ethAddress': ethAddress, - })) as executeDCASwapJobDef.JobType[]; + })) as JobType[]; logger.log(`Found ${jobs.length} jobs with ID ${scheduleId}`); if (mustExist && !jobs.length) { @@ -51,7 +48,7 @@ export async function editJob({ data, scheduleId, }: { - data: Omit; + data: Omit; scheduleId: string; }) { const { @@ -70,7 +67,7 @@ export async function editJob({ job.attrs.data = { ...data, updatedAt: new Date() }; - return (await job.save()) as unknown as executeDCASwapJobDef.JobType; + return (await job.save()) as unknown as JobType; } export async function disableJob({ @@ -113,7 +110,7 @@ export async function cancelJob({ } export async function createJob( - data: Omit, + data: Omit, options: { interval?: string; schedule?: string; @@ -122,7 +119,7 @@ export async function createJob( const agenda = getAgenda(); // Create a new job instance - const job = agenda.create(executeDCASwapJobDef.jobName, { + const job = agenda.create(jobName, { ...data, updatedAt: new Date(), }); diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/constants.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/constants.ts new file mode 100644 index 0000000..debf166 --- /dev/null +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/constants.ts @@ -0,0 +1,4 @@ +export const BASE_CHAIN_ID = 8453; +export const BASE_USDC_ADDRESS = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'; +export const BASE_WBTC_ADDRESS = '0x0555E30da8f98308EdB960aa94C0Db47230d2B9c'; +export const BASE_UNISWAP_V3_ROUTER = '0x2626664c2603336E57B271c5C0b26F421741e481'; diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/executeDCASwap.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/executeDCASwap.ts deleted file mode 100644 index 4f100ac..0000000 --- a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/executeDCASwap.ts +++ /dev/null @@ -1,257 +0,0 @@ -import * as Sentry from '@sentry/node'; -import { Job } from '@whisthub/agenda'; -import consola from 'consola'; -import { ethers } from 'ethers'; - -import { IRelayPKP } from '@lit-protocol/types'; - -import { type AppData, assertPermittedVersion } from '../jobVersion'; -import { - alchemyGasSponsor, - alchemyGasSponsorApiKey, - alchemyGasSponsorPolicyId, - balanceOf, - getERC20Contract, - getUserPermittedVersion, - handleOperationExecution, -} from './utils'; -import { - getErc20ApprovalToolClient, - getSignedUniswapQuote, - getUniswapToolClient, -} from './vincentAbilities'; -import { env } from '../../../env'; -import { normalizeError } from '../../../error'; -import { PurchasedCoin } from '../../../mongo/models/PurchasedCoin'; - -export type JobType = Job; -export type JobParams = { - app: AppData; - name: string; - pkpInfo: IRelayPKP; - purchaseAmount: number; - purchaseIntervalHuman: string; - updatedAt: Date; -}; - -const { BASE_RPC_URL, VINCENT_APP_ID } = env; - -const BASE_CHAIN_ID = 8453; -const BASE_USDC_ADDRESS = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'; -const BASE_WBTC_ADDRESS = '0x0555E30da8f98308EdB960aa94C0Db47230d2B9c'; -const BASE_UNISWAP_V3_ROUTER = '0x2626664c2603336E57B271c5C0b26F421741e481'; - -const baseProvider = new ethers.providers.StaticJsonRpcProvider(BASE_RPC_URL); -const usdcContract = getERC20Contract(BASE_USDC_ADDRESS, baseProvider); - -async function addUsdcApproval({ - ethAddress, - usdcAmount, -}: { - ethAddress: `0x${string}`; - usdcAmount: ethers.BigNumber; -}): Promise<`0x${string}` | undefined> { - const erc20ApprovalToolClient = getErc20ApprovalToolClient(); - const approvalParams = { - alchemyGasSponsor, - alchemyGasSponsorApiKey, - alchemyGasSponsorPolicyId, - chainId: BASE_CHAIN_ID, - rpcUrl: BASE_RPC_URL, - spenderAddress: BASE_UNISWAP_V3_ROUTER, - tokenAddress: BASE_USDC_ADDRESS, - tokenAmount: usdcAmount.mul(5).toString(), // Approve 5x the amount to spend so we don't wait for approval tx's every time we run - }; - const approvalContext = { - delegatorPkpEthAddress: ethAddress, - }; - - // Running precheck to prevent sending approval tx if not needed or will fail - const approvalPrecheckResult = await erc20ApprovalToolClient.precheck( - approvalParams, - approvalContext - ); - if (!approvalPrecheckResult.success) { - throw new Error(`ERC20 approval tool precheck failed: ${approvalPrecheckResult}`); - } else if (approvalPrecheckResult.result.alreadyApproved) { - // No need to send tx, allowance is already at that amount - return undefined; - } - - // Sending approval tx - const approvalExecutionResult = await erc20ApprovalToolClient.execute( - approvalParams, - approvalContext - ); - consola.trace('ERC20 Approval Vincent Tool Response:', approvalExecutionResult); - if (!approvalExecutionResult.success) { - throw new Error(`ERC20 approval tool execution failed: ${approvalExecutionResult}`); - } - - return approvalExecutionResult.result.approvalTxHash as `0x${string}`; -} - -async function handleSwapExecution({ - delegatorAddress, - tokenInAddress, - tokenInAmount, - tokenInDecimals, - tokenOutAddress, -}: { - delegatorAddress: `0x${string}`; - tokenInAddress: `0x${string}`; - tokenInAmount: ethers.BigNumber; - tokenInDecimals: number; - tokenOutAddress: `0x${string}`; -}): Promise<`0x${string}`> { - const signedUniswapQuote = await getSignedUniswapQuote({ - tokenInAddress, - tokenOutAddress, - recipient: delegatorAddress, - rpcUrl: BASE_RPC_URL, - tokenInAmount: ethers.utils.formatUnits(tokenInAmount, tokenInDecimals), - }); - - const uniswapToolClient = getUniswapToolClient(); - const swapParams = { - signedUniswapQuote, - rpcUrlForUniswap: BASE_RPC_URL, - }; - const swapContext = { - delegatorPkpEthAddress: delegatorAddress, - }; - - const swapPrecheckResult = await uniswapToolClient.precheck(swapParams, swapContext); - if (!swapPrecheckResult.success) { - throw new Error(`Uniswap tool precheck failed: ${swapPrecheckResult}`); - } - - const swapExecutionResult = await uniswapToolClient.execute(swapParams, swapContext); - consola.trace('Uniswap Swap Vincent Tool Response:', swapExecutionResult); - if (!swapExecutionResult.success) { - throw new Error(`Uniswap tool execution failed: ${swapExecutionResult}`); - } - - return swapExecutionResult.result.swapTxHash as `0x${string}`; -} - -export async function executeDCASwap(job: JobType, sentryScope: Sentry.Scope): Promise { - try { - const { - _id, - data: { - app, - pkpInfo: { ethAddress, publicKey }, - purchaseAmount, - }, - } = job.attrs; - - consola.log('Starting DCA swap job...', { - _id, - ethAddress, - purchaseAmount, - }); - - consola.debug('Fetching user USDC balance...'); - const [usdcBalance, userPermittedAppVersion] = await Promise.all([ - balanceOf(usdcContract, ethAddress), - getUserPermittedVersion({ ethAddress, appId: VINCENT_APP_ID }), - ]); - - sentryScope.addBreadcrumb({ - data: { - usdcBalance, - }, - message: 'User USDC balance', - }); - - const _purchaseAmount = ethers.utils.parseUnits(purchaseAmount.toFixed(6), 6); - if (usdcBalance.lt(_purchaseAmount)) { - throw new Error( - `Not enough balance for account ${ethAddress} - please fund this account with USDC to DCA` - ); - } - if (!userPermittedAppVersion) { - throw new Error( - `User ${ethAddress} revoked permission to run this app. Used version to generate: ${app.version}` - ); - } - - // Run the saved version or update to the currently permitted one if version is compatible - const appVersionToRun = assertPermittedVersion(app.version, userPermittedAppVersion); - sentryScope.addBreadcrumb({ - data: { - app, - appVersionToRun, - userPermittedAppVersion, - }, - }); - if (appVersionToRun !== app.version) { - // User updated the permitted app version after creating the job, so we need to update it - // eslint-disable-next-line no-param-reassign - job.attrs.data.app = { ...job.attrs.data.app, version: appVersionToRun }; - await job.save(); - } - - consola.log('Job details', { - ethAddress, - purchaseAmount, - userPermittedAppVersion, - usdcBalance: ethers.utils.formatUnits(usdcBalance, 6), - }); - - const approvalHash = await addUsdcApproval({ - ethAddress: ethAddress as `0x${string}`, - usdcAmount: _purchaseAmount, - }); - sentryScope.addBreadcrumb({ - data: { - approvalHash, - }, - }); - - if (approvalHash) { - await handleOperationExecution({ - isSponsored: alchemyGasSponsor, - operationHash: approvalHash, - pkpPublicKey: publicKey, - provider: baseProvider, - }); - } - - const swapHash = await handleSwapExecution({ - delegatorAddress: ethAddress as `0x${string}`, - tokenInAddress: BASE_USDC_ADDRESS, - tokenInAmount: _purchaseAmount, - tokenInDecimals: 6, - tokenOutAddress: BASE_WBTC_ADDRESS, - }); - sentryScope.addBreadcrumb({ - data: { - swapHash, - }, - }); - - // Create a purchase record with all required fields - const purchase = new PurchasedCoin({ - ethAddress, - coinAddress: BASE_WBTC_ADDRESS, - name: 'wBTC', - purchaseAmount: purchaseAmount.toFixed(2), - scheduleId: _id, - symbol: 'wBTC', - txHash: swapHash, - }); - await purchase.save(); - - consola.debug(`Successfully purchased ${purchaseAmount} USDC of wBTC at tx hash ${swapHash}`); - } catch (e) { - // Catch-and-rethrow is usually an antipattern, but Agenda doesn't log failed job reasons to console - // so this is our chance to log the job failure details using Consola before we throw the error - // to Agenda, which will write the failure reason to the Agenda job document in Mongo - const err = normalizeError(e); - sentryScope.captureException(err); - consola.error(err.message, err.stack); - throw e; - } -} diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/index.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/index.ts index 2a2c286..74e8e07 100644 --- a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/index.ts +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/index.ts @@ -1,7 +1,126 @@ -import { executeDCASwap } from './executeDCASwap'; +import * as Sentry from '@sentry/node'; +import consola from 'consola'; +import { ethers } from 'ethers'; -import type { JobType, JobParams } from './executeDCASwap'; +import { BASE_USDC_ADDRESS, BASE_WBTC_ADDRESS } from './constants'; +import { assertPermittedVersion } from './jobVersion'; +import { JobHandler, JobType, SupportedJobVersions } from './types'; +import { balanceOf, getERC20Contract, getUserPermittedVersion } from './utils'; +import { processJob as executeDCASwapV1 } from './v1'; +import { processJob as executeDCASwapV2 } from './v2'; +import { env } from '../../../env'; +import { normalizeError } from '../../../error'; +import { PurchasedCoin } from '../../../mongo/models/PurchasedCoin'; export const jobName = 'execute-swap'; -export const processJob = executeDCASwap; -export type { JobType, JobParams }; + +const { BASE_RPC_URL, VINCENT_APP_ID } = env; + +const baseProvider = new ethers.providers.StaticJsonRpcProvider(BASE_RPC_URL); +const usdcContract = getERC20Contract(BASE_USDC_ADDRESS, baseProvider); + +// The mapping of job API versions to their handlers is here as an example, and is how the live production +// `Vincent wBTC DCA` app manages its jobs. +// This repository will always use `2` unless you enable versioning by setting the `ENABLE_APP_VERSIONING` env var +// Note that if you do enable app versioning, you will need to update `getJobAPIVersionFromVincentAppVersion()` accordingly. +const jobHandlerByApiVersion: Record = { + 1: executeDCASwapV1, + 2: executeDCASwapV2, +}; + +export async function processJob(job: JobType, sentryScope: Sentry.Scope) { + try { + const { + _id, + data: { + app, + pkpInfo: { ethAddress }, + purchaseAmount, + }, + } = job.attrs; + + consola.log('Starting DCA swap job...', { + _id, + ethAddress, + purchaseAmount, + }); + + consola.debug('Fetching user USDC balance...'); + const [usdcBalance, userPermittedAppVersion] = await Promise.all([ + balanceOf(usdcContract, ethAddress), + getUserPermittedVersion({ ethAddress, appId: VINCENT_APP_ID }), + ]); + + sentryScope.addBreadcrumb({ + data: { + usdcBalance, + }, + message: 'User USDC balance', + }); + + const _purchaseAmount = ethers.utils.parseUnits(purchaseAmount.toFixed(6), 6); + if (usdcBalance.lt(_purchaseAmount)) { + throw new Error( + `Not enough balance for account ${ethAddress} - please fund this account with USDC to DCA` + ); + } + if (!userPermittedAppVersion) { + throw new Error( + `User ${ethAddress} revoked permission to run this app. Used version to generate: ${app.version}` + ); + } + + // Run the saved version or update to the currently permitted one if version is compatible + const { jobAPIVersion, userPermittedVersion: appVersionToRun } = assertPermittedVersion( + app.version, + userPermittedAppVersion + ); + sentryScope.addBreadcrumb({ + data: { + app, + appVersionToRun, + userPermittedAppVersion, + }, + }); + + if (appVersionToRun !== app.version) { + // User updated the permitted app version after creating the job, so we need to update it + // eslint-disable-next-line no-param-reassign + job.attrs.data.app = { ...job.attrs.data.app, version: appVersionToRun }; + await job.save(); + } + + consola.log('Job details', { + ethAddress, + purchaseAmount, + userPermittedAppVersion, + usdcBalance: ethers.utils.formatUnits(usdcBalance, 6), + }); + + if (!(jobAPIVersion in jobHandlerByApiVersion)) { + throw new Error(`Unknown job api version ${jobAPIVersion}`); + } + + const { swapHash } = await jobHandlerByApiVersion[jobAPIVersion](job, sentryScope); + + // Create a purchase record with all required fields + const purchase = new PurchasedCoin({ + ethAddress, + coinAddress: BASE_WBTC_ADDRESS, + name: 'wBTC', + purchaseAmount: purchaseAmount.toFixed(2), + scheduleId: _id, + symbol: 'wBTC', + txHash: swapHash, + }); + await purchase.save(); + } catch (e) { + // Catch-and-rethrow is usually an antipattern, but Agenda doesn't log failed job reasons to console + // so this is our chance to log the job failure details using Consola before we throw the error + // to Agenda, which will write the failure reason to the Agenda job document in Mongo + const err = normalizeError(e); + sentryScope.captureException(err); + consola.error(err.message, err.stack); + throw e; + } +} diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/jobVersion.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/jobVersion.ts new file mode 100644 index 0000000..0c37a51 --- /dev/null +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/jobVersion.ts @@ -0,0 +1,50 @@ +import { major } from 'semver'; + +import { SupportedJobVersions } from './types'; +import { env } from '../../../env'; + +const { ENABLE_APP_VERSIONING } = env; + +/** + * AppVersion is the numeric, incremental app version that is assigned each time you create/publish + * a new Vincent App Version jobAPIVersion is an internal concept to this application; if the code + * needed to execute jobs for your app changes enough between appVersions to make it necessary to + * have different code paths to handle the new appVersion then a new jobVersion would be indicated. + * See `packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/index.ts` for an example of how this + * works for the Vincent wBTC DCA app + */ +export function getJobAPIVersionFromVincentAppVersion(appVersion: number): string { + // Unless custom versioning is enabled, we assume we should support the most recent version of the uniswap ability + if (!ENABLE_APP_VERSIONING) { + return '2.0.0'; + } + + if (appVersion <= 3) { + return '1.0.0'; + } + return '2.0.0'; +} + +function assertJobVersionSupported(jobVersion: number): asserts jobVersion is SupportedJobVersions { + if (jobVersion !== 1 && jobVersion !== 2) { + throw new Error('Incompatible job version'); + } +} +export function assertPermittedVersion( + vincentAppVersion: number, + userPermittedVersion: number +): { jobAPIVersion: SupportedJobVersions; userPermittedVersion: number } { + const jobAPIVersion = getJobAPIVersionFromVincentAppVersion(vincentAppVersion); + const userPermittedJobVersion = getJobAPIVersionFromVincentAppVersion(userPermittedVersion); + + if (major(jobAPIVersion) !== major(userPermittedJobVersion)) { + throw new Error( + `Incompatible job version: ${vincentAppVersion} (${jobAPIVersion}) vs ${userPermittedVersion} (${userPermittedJobVersion})` + ); + } + + const userPermittedJobAPIVersion = major(userPermittedJobVersion); + assertJobVersionSupported(userPermittedJobAPIVersion); + + return { userPermittedVersion, jobAPIVersion: userPermittedJobAPIVersion }; +} diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/types.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/types.ts new file mode 100644 index 0000000..063a0bd --- /dev/null +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/types.ts @@ -0,0 +1,25 @@ +import * as Sentry from '@sentry/node'; +import { Job } from '@whisthub/agenda'; + +import { IRelayPKP } from '@lit-protocol/types'; + +export type JobType = Job; +export type AppData = { + id: number; + version: number; +}; +export type JobParams = { + app: AppData; + name: string; + pkpInfo: IRelayPKP; + purchaseAmount: number; + purchaseIntervalHuman: string; + updatedAt: Date; +}; + +export type JobHandler = ( + job: JobType, + sentryScope: Sentry.Scope +) => Promise<{ swapHash: `0x${string}` }>; + +export type SupportedJobVersions = 1 | 2; diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/utils/handle-operation-execution.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/utils/handle-operation-execution.ts index afe6fea..a87c1b0 100644 --- a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/utils/handle-operation-execution.ts +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/utils/handle-operation-execution.ts @@ -23,6 +23,7 @@ export async function handleOperationExecution({ let useropHash; if (!isSponsored) { txHash = operationHash; + await waitForTransaction({ confirmations, provider, transactionHash: txHash }); } else { useropHash = operationHash; txHash = await waitForUserOperation({ diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v1/index.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v1/index.ts new file mode 100644 index 0000000..facbe9b --- /dev/null +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v1/index.ts @@ -0,0 +1,3 @@ +import { executeDCASwap } from './jobHandler'; + +export const processJob = executeDCASwap; diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v1/jobHandler.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v1/jobHandler.ts new file mode 100644 index 0000000..de9a055 --- /dev/null +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v1/jobHandler.ts @@ -0,0 +1,166 @@ +import * as Sentry from '@sentry/node'; +import consola from 'consola'; +import { ethers } from 'ethers'; + +import { + alchemyGasSponsor, + alchemyGasSponsorApiKey, + alchemyGasSponsorPolicyId, + handleOperationExecution, +} from '../utils'; +import { + getErc20ApprovalToolClient, + getSignedUniswapQuote, + getUniswapToolClient, +} from './vincentAbilities'; +import { env } from '../../../../env'; +import { + BASE_CHAIN_ID, + BASE_UNISWAP_V3_ROUTER, + BASE_USDC_ADDRESS, + BASE_WBTC_ADDRESS, +} from '../constants'; +import { JobType } from '../types'; + +const { BASE_RPC_URL } = env; + +const baseProvider = new ethers.providers.StaticJsonRpcProvider(BASE_RPC_URL); + +async function addUsdcApproval({ + ethAddress, + usdcAmount, +}: { + ethAddress: `0x${string}`; + usdcAmount: ethers.BigNumber; +}): Promise<`0x${string}` | undefined> { + const erc20ApprovalToolClient = await getErc20ApprovalToolClient(); + const approvalParams = { + alchemyGasSponsor, + alchemyGasSponsorApiKey, + alchemyGasSponsorPolicyId, + chainId: BASE_CHAIN_ID, + rpcUrl: BASE_RPC_URL, + spenderAddress: BASE_UNISWAP_V3_ROUTER, + tokenAddress: BASE_USDC_ADDRESS, + tokenAmount: usdcAmount.mul(5).toString(), // Approve 5x the amount to spend so we don't wait for approval tx's every time we run + }; + const approvalContext = { + delegatorPkpEthAddress: ethAddress, + }; + + // Running precheck to prevent sending approval tx if not needed or will fail + const approvalPrecheckResult = await erc20ApprovalToolClient.precheck( + approvalParams, + approvalContext + ); + if (!approvalPrecheckResult.success) { + throw new Error(`ERC20 approval tool precheck failed: ${approvalPrecheckResult}`); + } else if (approvalPrecheckResult.result.alreadyApproved) { + // No need to send tx, allowance is already at that amount + return undefined; + } + + // Sending approval tx + const approvalExecutionResult = await erc20ApprovalToolClient.execute( + approvalParams, + approvalContext + ); + consola.trace('ERC20 Approval Vincent Tool Response:', approvalExecutionResult); + if (!approvalExecutionResult.success) { + throw new Error(`ERC20 approval tool execution failed: ${approvalExecutionResult}`); + } + + return approvalExecutionResult.result.approvalTxHash as `0x${string}`; +} + +async function handleSwapExecution({ + delegatorAddress, + tokenInAddress, + tokenInAmount, + tokenInDecimals, + tokenOutAddress, +}: { + delegatorAddress: `0x${string}`; + tokenInAddress: `0x${string}`; + tokenInAmount: ethers.BigNumber; + tokenInDecimals: number; + tokenOutAddress: `0x${string}`; +}): Promise<`0x${string}`> { + const signedUniswapQuote = await getSignedUniswapQuote({ + tokenInAddress, + tokenOutAddress, + recipient: delegatorAddress, + rpcUrl: BASE_RPC_URL, + tokenInAmount: ethers.utils.formatUnits(tokenInAmount, tokenInDecimals), + }); + + const uniswapToolClient = await getUniswapToolClient(); + const swapParams = { + signedUniswapQuote, + rpcUrlForUniswap: BASE_RPC_URL, + }; + const swapContext = { + delegatorPkpEthAddress: delegatorAddress, + }; + + const swapPrecheckResult = await uniswapToolClient.precheck(swapParams, swapContext); + if (!swapPrecheckResult.success) { + throw new Error(`Uniswap tool precheck failed: ${swapPrecheckResult}`); + } + + const swapExecutionResult = await uniswapToolClient.execute(swapParams, swapContext); + consola.trace('Uniswap Swap Vincent Tool Response:', swapExecutionResult); + if (!swapExecutionResult.success) { + throw new Error(`Uniswap tool execution failed: ${swapExecutionResult}`); + } + + return swapExecutionResult.result.swapTxHash as `0x${string}`; +} + +export async function executeDCASwap(job: JobType, sentryScope: Sentry.Scope) { + const { + data: { + pkpInfo: { ethAddress, publicKey }, + purchaseAmount, + }, + } = job.attrs; + + const _purchaseAmount = ethers.utils.parseUnits(purchaseAmount.toFixed(6), 6); + + const approvalHash = await addUsdcApproval({ + ethAddress: ethAddress as `0x${string}`, + usdcAmount: _purchaseAmount, + }); + sentryScope.addBreadcrumb({ + data: { + approvalHash, + }, + }); + + if (approvalHash) { + await handleOperationExecution({ + isSponsored: alchemyGasSponsor, + operationHash: approvalHash, + pkpPublicKey: publicKey, + provider: baseProvider, + }); + } + + const swapHash = await handleSwapExecution({ + delegatorAddress: ethAddress as `0x${string}`, + tokenInAddress: BASE_USDC_ADDRESS, + tokenInAmount: _purchaseAmount, + tokenInDecimals: 6, + tokenOutAddress: BASE_WBTC_ADDRESS, + }); + + consola.debug(`Successfully purchased ${purchaseAmount} USDC of wBTC at tx hash ${swapHash}`); + + sentryScope.addBreadcrumb({ + data: { + swapHash, + }, + }); + + return { swapHash }; +} diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v1/utils.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v1/utils.ts new file mode 100644 index 0000000..2fe3506 --- /dev/null +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v1/utils.ts @@ -0,0 +1,37 @@ +import { ethers } from 'ethers'; + +import { env } from '../../../../env'; +import { waitForTransaction } from '../utils/wait-for-transaction'; +import { waitForUserOperation } from '../utils/wait-for-user-operation'; + +const { DEFAULT_TX_CONFIRMATIONS } = env; + +export async function handleOperationExecution({ + confirmations = DEFAULT_TX_CONFIRMATIONS, + isSponsored, + operationHash, + pkpPublicKey, + provider, +}: { + confirmations?: number; + isSponsored: boolean; + operationHash: `0x${string}`; + pkpPublicKey: string; + provider: ethers.providers.JsonRpcProvider; +}): Promise<{ txHash: `0x${string}`; useropHash: `0x${string}` | undefined }> { + let txHash; + let useropHash; + if (!isSponsored) { + txHash = operationHash; + } else { + useropHash = operationHash; + txHash = await waitForUserOperation({ + pkpPublicKey, + provider, + useropHash, + }); + await waitForTransaction({ confirmations, provider, transactionHash: txHash }); + } + + return { txHash, useropHash }; +} diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/vincentAbilities.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v1/vincentAbilities.ts similarity index 73% rename from packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/vincentAbilities.ts rename to packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v1/vincentAbilities.ts index 28b71b9..3533f2b 100644 --- a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/vincentAbilities.ts +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v1/vincentAbilities.ts @@ -3,20 +3,19 @@ import { bundledVincentAbility as erc20ApprovalBundledVincentAbility } from '@li import { bundledVincentAbility as uniswapSwapBundledVincentAbility, getSignedUniswapQuote as getSignedUniswapQuoteAction, - QuoteParams, -} from '@lit-protocol/vincent-ability-uniswap-swap'; +} from '@lit-protocol/vincent-ability-uniswap-swap-v5'; import { getVincentAbilityClient } from '@lit-protocol/vincent-app-sdk/abilityClient'; -import { delegateeSigner } from './utils/signer'; +import { delegateeSigner } from '../utils/signer'; + +import type { QuoteParams } from '@lit-protocol/vincent-ability-uniswap-swap-v5'; const litNodeClient = new LitNodeClient({ debug: true, litNetwork: 'datil', }); -export async function getSignedUniswapQuote( - quoteParams: QuoteParams -): Promise> { +export async function getSignedUniswapQuote(quoteParams: QuoteParams) { // Ensure litNodeClient is connected if (!litNodeClient.ready) { await litNodeClient.connect(); @@ -29,14 +28,14 @@ export async function getSignedUniswapQuote( }); } -export function getErc20ApprovalToolClient() { +export async function getErc20ApprovalToolClient() { return getVincentAbilityClient({ bundledVincentAbility: erc20ApprovalBundledVincentAbility, ethersSigner: delegateeSigner, }); } -export function getUniswapToolClient() { +export async function getUniswapToolClient() { return getVincentAbilityClient({ bundledVincentAbility: uniswapSwapBundledVincentAbility, ethersSigner: delegateeSigner, diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v2/index.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v2/index.ts new file mode 100644 index 0000000..facbe9b --- /dev/null +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v2/index.ts @@ -0,0 +1,3 @@ +import { executeDCASwap } from './jobHandler'; + +export const processJob = executeDCASwap; diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v2/jobHandler.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v2/jobHandler.ts new file mode 100644 index 0000000..0f46c32 --- /dev/null +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v2/jobHandler.ts @@ -0,0 +1,149 @@ +import * as Sentry from '@sentry/node'; +import consola from 'consola'; +import { ethers } from 'ethers'; + +import { AbilityAction } from '@lit-protocol/vincent-ability-uniswap-swap-v8'; + +import { + alchemyGasSponsor, + alchemyGasSponsorApiKey, + alchemyGasSponsorPolicyId, + handleOperationExecution, +} from '../utils'; +import { getSignedUniswapQuote, getUniswapAbilityClient } from './vincentAbilities'; +import { env } from '../../../../env'; +import { BASE_USDC_ADDRESS, BASE_WBTC_ADDRESS } from '../constants'; +import { JobType } from '../types'; + +const { BASE_RPC_URL } = env; + +const baseProvider = new ethers.providers.StaticJsonRpcProvider(BASE_RPC_URL); + +async function handleSwapExecution({ + delegatorAddress, + pkpPublicKey, + tokenInAddress, + tokenInAmount, + tokenInDecimals, + tokenOutAddress, +}: { + delegatorAddress: `0x${string}`; + pkpPublicKey: `0x${string}`; + tokenInAddress: `0x${string}`; + tokenInAmount: ethers.BigNumber; + tokenInDecimals: number; + tokenOutAddress: `0x${string}`; +}): Promise<`0x${string}`> { + const signedUniswapQuote = await getSignedUniswapQuote({ + tokenInAddress, + tokenOutAddress, + recipient: delegatorAddress, + rpcUrl: BASE_RPC_URL, + tokenInAmount: ethers.utils.formatUnits(tokenInAmount, tokenInDecimals), + }); + + const uniswapToolClient = await getUniswapAbilityClient(); + const swapContext = { + delegatorPkpEthAddress: delegatorAddress, + }; + + const approveParams = { + alchemyGasSponsor, + alchemyGasSponsorApiKey, + alchemyGasSponsorPolicyId, + signedUniswapQuote, + action: 'approve' as const, + rpcUrlForUniswap: BASE_RPC_URL, + }; + + const approvePrecheckResult = await uniswapToolClient.precheck(approveParams, swapContext); + consola.trace('Uniswap Approve Precheck Response:', approvePrecheckResult); + if (!approvePrecheckResult.success) { + throw new Error(`Uniswap approve precheck failed: ${approvePrecheckResult.result?.reason}`); + } + + const approveExecutionResult = await uniswapToolClient.execute(approveParams, swapContext); + consola.trace('Uniswap Approve Vincent Tool Response:', approveExecutionResult); + if (approveExecutionResult.success === false) { + throw new Error(`Uniswap tool approval failed: ${approveExecutionResult.runtimeError}`); + } + + const approveResult = approveExecutionResult.result!; + const approveOperationHash = (approveResult.approvalTxUserOperationHash || + approveResult.approvalTxHash) as `0x${string}` | undefined; + + if (approveOperationHash) { + consola.debug('Waiting for approval transaction to be mined...'); + await handleOperationExecution({ + pkpPublicKey, + isSponsored: alchemyGasSponsor, + operationHash: approveOperationHash, + provider: baseProvider, + }); + consola.debug('Approval transaction mined successfully'); + } else { + consola.debug('Approval already sufficient, no transaction needed'); + } + + const swapParams = { + alchemyGasSponsor, + alchemyGasSponsorApiKey, + alchemyGasSponsorPolicyId, + signedUniswapQuote, + action: AbilityAction.Swap as 'swap', + rpcUrlForUniswap: BASE_RPC_URL, + }; + + const swapPrecheckResult = await uniswapToolClient.precheck(swapParams, swapContext); + consola.trace('Uniswap Swap Precheck Response:', swapPrecheckResult); + if (!swapPrecheckResult.success) { + throw new Error(`Uniswap swap precheck failed: ${swapPrecheckResult.result?.reason}`); + } + + const swapExecutionResult = await uniswapToolClient.execute(swapParams, swapContext); + consola.trace('Uniswap Swap Vincent Tool Response:', swapExecutionResult); + if (swapExecutionResult.success === false) { + throw new Error(`Uniswap tool execution failed: ${swapExecutionResult.runtimeError}`); + } + + const result = swapExecutionResult.result!; + const operationHash = (result.swapTxUserOperationHash || result.swapTxHash) as `0x${string}`; + + return operationHash; +} + +export async function executeDCASwap(job: JobType, sentryScope: Sentry.Scope) { + const { + data: { + pkpInfo: { ethAddress, publicKey }, + purchaseAmount, + }, + } = job.attrs; + + const _purchaseAmount = ethers.utils.parseUnits(purchaseAmount.toFixed(6), 6); + const swapOperationHash = await handleSwapExecution({ + delegatorAddress: ethAddress as `0x${string}`, + pkpPublicKey: publicKey as `0x${string}`, + tokenInAddress: BASE_USDC_ADDRESS, + tokenInAmount: _purchaseAmount, + tokenInDecimals: 6, + tokenOutAddress: BASE_WBTC_ADDRESS, + }); + + const { txHash: swapHash } = await handleOperationExecution({ + isSponsored: alchemyGasSponsor, + operationHash: swapOperationHash, + pkpPublicKey: publicKey, + provider: baseProvider, + }); + + consola.debug(`Successfully purchased ${purchaseAmount} USDC of wBTC at tx hash ${swapHash}`); + + sentryScope.addBreadcrumb({ + data: { + swapHash, + }, + }); + + return { swapHash }; +} diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v2/utils.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v2/utils.ts new file mode 100644 index 0000000..4f506b4 --- /dev/null +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v2/utils.ts @@ -0,0 +1,38 @@ +import { ethers } from 'ethers'; + +import { env } from '../../../../env'; +import { waitForTransaction } from '../utils/wait-for-transaction'; +import { waitForUserOperation } from '../utils/wait-for-user-operation'; + +const { DEFAULT_TX_CONFIRMATIONS } = env; + +export async function handleOperationExecution({ + confirmations = DEFAULT_TX_CONFIRMATIONS, + isSponsored, + operationHash, + pkpPublicKey, + provider, +}: { + confirmations?: number; + isSponsored: boolean; + operationHash: `0x${string}`; + pkpPublicKey: string; + provider: ethers.providers.JsonRpcProvider; +}): Promise<{ txHash: `0x${string}`; useropHash: `0x${string}` | undefined }> { + let txHash; + let useropHash; + if (!isSponsored) { + txHash = operationHash; + await waitForTransaction({ confirmations, provider, transactionHash: txHash }); + } else { + useropHash = operationHash; + txHash = await waitForUserOperation({ + pkpPublicKey, + provider, + useropHash, + }); + await waitForTransaction({ confirmations, provider, transactionHash: txHash }); + } + + return { txHash, useropHash }; +} diff --git a/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v2/vincentAbilities.ts b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v2/vincentAbilities.ts new file mode 100644 index 0000000..e28978a --- /dev/null +++ b/packages/dca-backend/src/lib/agenda/jobs/executeDCASwap/v2/vincentAbilities.ts @@ -0,0 +1,37 @@ +import { LitNodeClient } from '@lit-protocol/lit-node-client'; +import { + bundledVincentAbility as uniswapSwapBundledVincentAbility, + getSignedUniswapQuote as getSignedUniswapQuoteAction, +} from '@lit-protocol/vincent-ability-uniswap-swap-v8'; +import { getVincentAbilityClient } from '@lit-protocol/vincent-app-sdk/abilityClient'; + +import { delegateeSigner } from '../utils/signer'; + +import type { QuoteParams } from '@lit-protocol/vincent-ability-uniswap-swap-v8'; + +const litNodeClient = new LitNodeClient({ + debug: true, + litNetwork: 'datil', +}); + +export async function getSignedUniswapQuote( + quoteParams: QuoteParams +): Promise> { + // Ensure litNodeClient is connected + if (!litNodeClient.ready) { + await litNodeClient.connect(); + } + + return getSignedUniswapQuoteAction({ + litNodeClient, + quoteParams, + ethersSigner: delegateeSigner, + }); +} + +export async function getUniswapAbilityClient() { + return getVincentAbilityClient({ + bundledVincentAbility: uniswapSwapBundledVincentAbility, + ethersSigner: delegateeSigner, + }); +} diff --git a/packages/dca-backend/src/lib/agenda/jobs/index.ts b/packages/dca-backend/src/lib/agenda/jobs/index.ts deleted file mode 100644 index 6a05cec..0000000 --- a/packages/dca-backend/src/lib/agenda/jobs/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as executeDCASwapJobDef from './executeDCASwap'; - -export { executeDCASwapJobDef }; diff --git a/packages/dca-backend/src/lib/agenda/jobs/jobVersion.ts b/packages/dca-backend/src/lib/agenda/jobs/jobVersion.ts deleted file mode 100644 index d733754..0000000 --- a/packages/dca-backend/src/lib/agenda/jobs/jobVersion.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { major } from 'semver'; - -export type AppData = { - id: number; - version: number; -}; - -export function getJobVersion(appVersion: number): string { - // For now, all app versions use the same job api/version - if (appVersion > 0) { - return '1.0.0'; - } - return '1.0.0'; -} - -export function assertPermittedVersion(appVersion: number, userPermittedVersion: number): number { - const appJobVersion = getJobVersion(appVersion); - const userPermittedJobVersion = getJobVersion(userPermittedVersion); - - if (major(appJobVersion) !== major(userPermittedJobVersion)) { - throw new Error( - `Incompatible job version: ${appVersion} (${appJobVersion}) vs ${userPermittedVersion} (${userPermittedJobVersion})` - ); - } - - return userPermittedVersion; -} diff --git a/packages/dca-backend/src/lib/env.ts b/packages/dca-backend/src/lib/env.ts index 463a6ba..99fa4ee 100644 --- a/packages/dca-backend/src/lib/env.ts +++ b/packages/dca-backend/src/lib/env.ts @@ -30,6 +30,7 @@ export const env = createEnv({ CHRONICLE_YELLOWSTONE_RPC: z.string().url().default(LIT_RPC.CHRONICLE_YELLOWSTONE), CORS_ALLOWED_DOMAIN: z.string().url(), DEFAULT_TX_CONFIRMATIONS: z.coerce.number().default(6), + ENABLE_APP_VERSIONING: z.boolean().optional().default(false), IS_DEVELOPMENT: BooleanOrBooleanStringSchema, MONGODB_URI: z.string().url(), PORT: z.coerce.number(), diff --git a/packages/dca-backend/src/lib/jobWorker.ts b/packages/dca-backend/src/lib/jobWorker.ts index a50d2f8..b88493b 100644 --- a/packages/dca-backend/src/lib/jobWorker.ts +++ b/packages/dca-backend/src/lib/jobWorker.ts @@ -2,7 +2,9 @@ import * as Sentry from '@sentry/node'; import consola from 'consola'; import { createAgenda, getAgenda } from './agenda/agendaClient'; -import { executeDCASwapJobDef } from './agenda/jobs'; +import { jobName, processJob } from './agenda/jobs/executeDCASwap'; + +import type { JobType } from './agenda/jobs/executeDCASwap/types'; // Function to create and configure a new agenda instance export async function startWorker() { @@ -10,12 +12,12 @@ export async function startWorker() { const agenda = getAgenda(); - agenda.define(executeDCASwapJobDef.jobName, async (job: executeDCASwapJobDef.JobType) => + agenda.define(jobName, async (job: JobType) => Sentry.withIsolationScope(async (scope) => { // TODO: add job-aware logic such as cool-downs in case of repeated failures here try { - await executeDCASwapJobDef.processJob(job, scope); + await processJob(job, scope); } catch (err) { scope.captureException(err); const error = err as Error; diff --git a/packages/dca-frontend/package.json b/packages/dca-frontend/package.json index 338693e..2dad124 100644 --- a/packages/dca-frontend/package.json +++ b/packages/dca-frontend/package.json @@ -26,7 +26,7 @@ "@lit-protocol/constants": "^7.3.0", "@lit-protocol/lit-node-client": "^7.3.0", "@lit-protocol/types": "^7.3.0", - "@lit-protocol/vincent-app-sdk": "2.0.2-mma", + "@lit-protocol/vincent-app-sdk": "2.2.2", "@radix-ui/react-checkbox": "^1.1.4", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-dropdown-menu": "^2.1.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5063cbc..d3a6a6a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,10 +24,10 @@ importers: version: 0.26.0 '@tsconfig/node20': specifier: ^20.1.5 - version: 20.1.5 + version: 20.1.6 '@types/node': - specifier: ^20.11.30 - version: 20.17.28 + specifier: ^22.16.0 + version: 22.18.12 '@types/verror': specifier: ^1.10.10 version: 1.10.11 @@ -108,19 +108,22 @@ importers: version: 7.3.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@lit-protocol/vincent-ability-erc20-approval': specifier: 3.1.0 - version: 3.1.0(@lit-protocol/vincent-app-sdk@2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10))(@lit-protocol/vincent-tool-sdk@1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/node@20.17.28)(@types/react@19.0.12)(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@lit-protocol/vincent-ability-uniswap-swap': - specifier: 5.0.0 - version: 5.0.0(@lit-protocol/vincent-app-sdk@2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(hardhat@2.26.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(jsbi@3.2.5)(typescript@5.8.2)(utf-8-validate@5.0.10) + version: 3.1.0(@lit-protocol/vincent-app-sdk@2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(@lit-protocol/vincent-tool-sdk@1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/node@22.18.12)(@types/react@19.0.12)(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10) + '@lit-protocol/vincent-ability-uniswap-swap-v5': + specifier: npm:@lit-protocol/vincent-ability-uniswap-swap@5.0.0 + version: '@lit-protocol/vincent-ability-uniswap-swap@5.0.0(@lit-protocol/vincent-app-sdk@2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(hardhat@2.26.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(jsbi@3.2.5)(typescript@5.8.2)(utf-8-validate@5.0.10)' + '@lit-protocol/vincent-ability-uniswap-swap-v8': + specifier: npm:@lit-protocol/vincent-ability-uniswap-swap@8.0.0 + version: '@lit-protocol/vincent-ability-uniswap-swap@8.0.0(@lit-protocol/vincent-app-sdk@2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(hardhat@2.26.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(jsbi@3.2.5)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76))' '@lit-protocol/vincent-app-sdk': - specifier: 2.2.1 - version: 2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10) + specifier: 2.2.3 + version: 2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@lit-protocol/vincent-contracts-sdk': - specifier: ^1.0.1 - version: 1.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + specifier: ^2.0.0 + version: 2.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@lit-protocol/vincent-scaffold-sdk': specifier: 1.1.9-mma - version: 1.1.9-mma(@lit-protocol/vincent-app-sdk@2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10))(@lit-protocol/vincent-tool-sdk@1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/node@20.17.28)(@types/react@19.0.12)(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + version: 1.1.9-mma(@lit-protocol/vincent-app-sdk@2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(@lit-protocol/vincent-tool-sdk@1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/node@22.18.12)(@types/react@19.0.12)(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@noble/secp256k1': specifier: ^2.2.3 version: 2.2.3 @@ -187,10 +190,10 @@ importers: version: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.17.28) + version: 29.7.0(@types/node@22.18.12) ts-jest: specifier: ^29.3.0 - version: 29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.19.12)(jest@29.7.0(@types/node@20.17.28))(typescript@5.8.2) + version: 29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.19.12)(jest@29.7.0(@types/node@22.18.12))(typescript@5.8.2) unbuild: specifier: ^3.5.0 version: 3.5.0(typescript@5.8.2) @@ -213,8 +216,8 @@ importers: specifier: ^7.3.0 version: 7.3.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@lit-protocol/vincent-app-sdk': - specifier: 2.0.2-mma - version: 2.0.2-mma(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10) + specifier: 2.2.2 + version: 2.2.2(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@radix-ui/react-checkbox': specifier: ^1.1.4 version: 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -1650,13 +1653,24 @@ packages: '@lit-protocol/vincent-ability-sdk@2.2.0': resolution: {integrity: sha512-y2jgEKQThG0Ew5jvbwcT+n6Q0APQAn7uQjO4WQ5MKEkGLa8HCy8g4PJpFFG1LtyfVomV5EmbQP/ZLCvegBEQJQ==} + '@lit-protocol/vincent-ability-sdk@2.3.0': + resolution: {integrity: sha512-HEHQDxzfqab7taptNH+GgQVtki+kzj4bU2seI0yc06+4S7X2JRJCTR9be2SEaKtuffAhZ6Fsl7NdE7oSW+klGw==} + + '@lit-protocol/vincent-ability-sdk@2.3.1': + resolution: {integrity: sha512-rhkpklYUa++BLDHDy7wRiaLnktHOHErxt+4j3Uo+qmj3nrrHUyVcqrsPQa5zVpCRJjr8k+JVcbR3XP32ubMEzw==} + '@lit-protocol/vincent-ability-uniswap-swap@5.0.0': resolution: {integrity: sha512-rDFhZAb/NHFFWFTaUNiuGb0UO+3YY/9JZ8UwyGwMp7QZWQesdUcqAoogmENDzuDT6nWignwq1FwbpfJtWYd1iA==} peerDependencies: '@lit-protocol/vincent-app-sdk': ^2.2.1 - '@lit-protocol/vincent-app-sdk@2.0.2-mma': - resolution: {integrity: sha512-naGTvNhXl1dSS4oHIiyHOBwHMRNxvS7zZh45ZPkGwhAe6KUUULlQ4dmbAQez791BGZliy4WYSnEN2BOAe5mFsA==} + '@lit-protocol/vincent-ability-uniswap-swap@8.0.0': + resolution: {integrity: sha512-YtgHhkPmw2uehh0AbyXMAfi/1MTVc7U2NxzB+TAgE1wl8E3EeNt3ZqY0g81Z8KRk96cR6D9p4zjTLy8kIcIfyA==} + peerDependencies: + '@lit-protocol/vincent-app-sdk': ^2.2.3 + + '@lit-protocol/vincent-app-sdk@2.2.2': + resolution: {integrity: sha512-IXY/q+fCgh1PeNvMToKwcQtHoZ5bVZRHXQsL3hHiMPyUvk6VCTFOEvqIN2zGlsheRbFcoiHIPCCGb0CUKp2Y0Q==} engines: {node: ^20.11.1, pnpm: 10.7.0} peerDependencies: react: ^19.0.0 @@ -1664,8 +1678,8 @@ packages: react: optional: true - '@lit-protocol/vincent-app-sdk@2.2.1': - resolution: {integrity: sha512-Yr9uPOnKVIf7v+ktXE4We7s/pHFCFlOrHIUlfSY3hvrVDaM3pxpTxqDO6JaZYVkH182oA2owxyDRYK60cGau0g==} + '@lit-protocol/vincent-app-sdk@2.2.3': + resolution: {integrity: sha512-z91gxLEr1ExtNPdWeYYxGCh15SDd2lxUxg2Dq8i7Uq0a2DokG1IfZ4gw0+l4ADU73GZJuAgMP0pyOXzcKEcbfQ==} engines: {node: ^20.11.1, pnpm: 10.7.0} peerDependencies: react: ^19.0.0 @@ -1679,6 +1693,9 @@ packages: '@lit-protocol/vincent-contracts-sdk@1.3.0': resolution: {integrity: sha512-UBoLlAKdwYh5FzVIdnyvnZDPXsHQEw/LuYgJiVFv5cBxU+4ifWWt9HejxuH51A/imS6ZU3yCbcdq7WwnbkaIEA==} + '@lit-protocol/vincent-contracts-sdk@2.0.0': + resolution: {integrity: sha512-xRgP+2CDRa4apo5MNHg/7wh699+OEq/eU/lMTsj0WJsJXs3D9Rh7kNrLRWFcnJhqf0T25whnUx/I7RDMWjGeSg==} + '@lit-protocol/vincent-scaffold-sdk@1.1.8': resolution: {integrity: sha512-SCLsBEogqvdpT+ug2aBY+QQ0X9T882ZEIManRqUiM60IDtYl0UQtc9rXo+R2dq5UO9aSznPc6wPCvFGGWfxnxw==} engines: {node: '>=16.0.0'} @@ -3257,8 +3274,8 @@ packages: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} - '@tsconfig/node20@20.1.5': - resolution: {integrity: sha512-Vm8e3WxDTqMGPU4GATF9keQAIy1Drd7bPwlgzKJnZtoOsTm1tduUTbDjg0W5qERvGuxPI2h9RbMufH0YdfBylA==} + '@tsconfig/node20@20.1.6': + resolution: {integrity: sha512-sz+Hqx9zwZDpZIV871WSbUzSqNIsXzghZydypnfgzPKLltVJfkINfUeTct31n/tTSa9ZE1ZOfKdRre1uHHquYQ==} '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} @@ -3371,6 +3388,9 @@ packages: '@types/node@22.13.14': resolution: {integrity: sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==} + '@types/node@22.18.12': + resolution: {integrity: sha512-BICHQ67iqxQGFSzfCFTT7MRQ5XcBjG5aeKh5Ok38UBbPe5fxTyE+aHFxwVrGyr8GNlqFMLKD1D3P2K/1ks8tog==} + '@types/node@22.7.5': resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} @@ -3646,8 +3666,8 @@ packages: resolution: {integrity: sha512-0KqXw+y0opBo6eoPAEoLHEkNpOu0NG9gEk7GAYIGok+SHX89WlykWsRYeJKTg9tOwhLpcG9oHg8xZgQ390iOrA==} engines: {node: '>=10'} - '@uniswap/smart-order-router@4.22.20': - resolution: {integrity: sha512-3QBo761/c+r6zDbo8oL5F/odFAqK/zNMcGSz+d4fKZPLfdfcpSZfD2z+rnk+YSOVt1cITIzwhWFFm6H82i7Thg==} + '@uniswap/smart-order-router@4.22.21': + resolution: {integrity: sha512-hdsKl/xkEn7AKFV3KooIfzYskSQ0SlMFIM/DrFVZxJpihjk8SBHNtFS8iU2hGrJ0X7/iwde059rJWhvREBAHlA==} engines: {node: '>=10'} peerDependencies: jsbi: ^3.2.0 @@ -8746,6 +8766,9 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici@5.29.0: resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} engines: {node: '>=14.0'} @@ -10588,12 +10611,12 @@ snapshots: chalk: 4.1.2 figures: 3.2.0 - '@inquirer/external-editor@1.0.1(@types/node@20.17.28)': + '@inquirer/external-editor@1.0.1(@types/node@22.18.12)': dependencies: chardet: 2.1.0 iconv-lite: 0.6.3 optionalDependencies: - '@types/node': 20.17.28 + '@types/node': 22.18.12 '@inquirer/figures@1.0.11': {} @@ -10666,7 +10689,7 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.28 + '@types/node': 22.18.12 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -10679,14 +10702,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.28 + '@types/node': 22.18.12 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.28) + jest-config: 29.7.0(@types/node@22.18.12) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -10711,7 +10734,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.28 + '@types/node': 22.18.12 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -10729,7 +10752,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.17.28 + '@types/node': 22.18.12 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -10751,7 +10774,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 20.17.28 + '@types/node': 22.18.12 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -10821,7 +10844,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.17.28 + '@types/node': 22.18.12 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -11266,11 +11289,11 @@ snapshots: - typescript - utf-8-validate - '@lit-protocol/vincent-ability-erc20-approval@3.1.0(@lit-protocol/vincent-app-sdk@2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10))(@lit-protocol/vincent-tool-sdk@1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/node@20.17.28)(@types/react@19.0.12)(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)': + '@lit-protocol/vincent-ability-erc20-approval@3.1.0(@lit-protocol/vincent-app-sdk@2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(@lit-protocol/vincent-tool-sdk@1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/node@22.18.12)(@types/react@19.0.12)(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)': dependencies: '@lit-protocol/vincent-ability-sdk': 2.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@lit-protocol/vincent-app-sdk': 2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@lit-protocol/vincent-scaffold-sdk': 1.1.8(@lit-protocol/vincent-app-sdk@2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10))(@lit-protocol/vincent-tool-sdk@1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/node@20.17.28)(@types/react@19.0.12)(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@lit-protocol/vincent-app-sdk': 2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@lit-protocol/vincent-scaffold-sdk': 1.1.8(@lit-protocol/vincent-app-sdk@2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(@lit-protocol/vincent-tool-sdk@1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/node@22.18.12)(@types/react@19.0.12)(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) tslib: 2.8.1 zod: 3.25.76 @@ -11312,13 +11335,91 @@ snapshots: - bufferutil - utf-8-validate - '@lit-protocol/vincent-ability-uniswap-swap@5.0.0(@lit-protocol/vincent-app-sdk@2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(hardhat@2.26.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(jsbi@3.2.5)(typescript@5.8.2)(utf-8-validate@5.0.10)': + '@lit-protocol/vincent-ability-sdk@2.3.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + dependencies: + '@account-kit/infra': 4.62.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@account-kit/smart-contracts': 4.62.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@lit-protocol/vincent-contracts-sdk': 1.3.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ethers-v6: ethers@6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + semver: 7.7.2 + tslib: 2.8.1 + zod: 3.25.76 + transitivePeerDependencies: + - bufferutil + - debug + - encoding + - supports-color + - typescript + - utf-8-validate + - viem + + '@lit-protocol/vincent-ability-sdk@2.3.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + dependencies: + '@account-kit/infra': 4.62.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@account-kit/smart-contracts': 4.62.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@lit-protocol/vincent-contracts-sdk': 2.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ethers-v6: ethers@6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + semver: 7.7.2 + tslib: 2.8.1 + zod: 3.25.76 + transitivePeerDependencies: + - bufferutil + - debug + - encoding + - supports-color + - typescript + - utf-8-validate + - viem + + '@lit-protocol/vincent-ability-uniswap-swap@5.0.0(@lit-protocol/vincent-app-sdk@2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(hardhat@2.26.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(jsbi@3.2.5)(typescript@5.8.2)(utf-8-validate@5.0.10)': dependencies: '@lit-protocol/lit-node-client': 7.3.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) '@lit-protocol/vincent-ability-sdk': 2.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@lit-protocol/vincent-app-sdk': 2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10) + '@lit-protocol/vincent-app-sdk': 2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@uniswap/sdk-core': 7.7.2 + '@uniswap/smart-order-router': 4.22.21(bufferutil@4.0.9)(hardhat@2.26.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(jsbi@3.2.5)(utf-8-validate@5.0.10) + ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + json-stable-stringify: 1.3.0 + tslib: 2.8.1 + zod: 3.25.76 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/kv' + - '@walletconnect/modal' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - hardhat + - ioredis + - jsbi + - supports-color + - typescript + - uploadthing + - utf-8-validate + + '@lit-protocol/vincent-ability-uniswap-swap@8.0.0(@lit-protocol/vincent-app-sdk@2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(hardhat@2.26.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(jsbi@3.2.5)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + dependencies: + '@lit-protocol/lit-node-client': 7.3.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) + '@lit-protocol/vincent-ability-sdk': 2.3.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@lit-protocol/vincent-app-sdk': 2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@uniswap/sdk-core': 7.7.2 - '@uniswap/smart-order-router': 4.22.20(bufferutil@4.0.9)(hardhat@2.26.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(jsbi@3.2.5)(utf-8-validate@5.0.10) + '@uniswap/smart-order-router': 4.22.21(bufferutil@4.0.9)(hardhat@2.26.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(jsbi@3.2.5)(utf-8-validate@5.0.10) ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) json-stable-stringify: 1.3.0 tslib: 2.8.1 @@ -11351,14 +11452,15 @@ snapshots: - typescript - uploadthing - utf-8-validate + - viem - '@lit-protocol/vincent-app-sdk@2.0.2-mma(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)': + '@lit-protocol/vincent-app-sdk@2.2.2(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: '@lit-protocol/auth-helpers': 7.3.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) '@lit-protocol/constants': 7.3.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) '@lit-protocol/lit-node-client': 7.3.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@lit-protocol/vincent-ability-sdk': 2.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@lit-protocol/vincent-contracts-sdk': 1.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@lit-protocol/vincent-ability-sdk': 2.3.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@lit-protocol/vincent-contracts-sdk': 1.3.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@noble/secp256k1': 2.2.3 ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) tslib: 2.8.1 @@ -11384,20 +11486,22 @@ snapshots: - aws4fetch - bufferutil - db0 + - debug - encoding - ioredis - supports-color - typescript - uploadthing - utf-8-validate + - viem - '@lit-protocol/vincent-app-sdk@2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)': + '@lit-protocol/vincent-app-sdk@2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: '@lit-protocol/auth-helpers': 7.3.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) '@lit-protocol/constants': 7.3.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) '@lit-protocol/lit-node-client': 7.3.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@lit-protocol/vincent-ability-sdk': 2.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@lit-protocol/vincent-contracts-sdk': 1.3.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@lit-protocol/vincent-ability-sdk': 2.3.1(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@lit-protocol/vincent-contracts-sdk': 2.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@noble/secp256k1': 2.2.3 ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) tslib: 2.8.1 @@ -11423,12 +11527,14 @@ snapshots: - aws4fetch - bufferutil - db0 + - debug - encoding - ioredis - supports-color - typescript - uploadthing - utf-8-validate + - viem '@lit-protocol/vincent-contracts-sdk@1.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: @@ -11448,12 +11554,21 @@ snapshots: - bufferutil - utf-8-validate - '@lit-protocol/vincent-scaffold-sdk@1.1.8(@lit-protocol/vincent-app-sdk@2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10))(@lit-protocol/vincent-tool-sdk@1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/node@20.17.28)(@types/react@19.0.12)(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@lit-protocol/vincent-contracts-sdk@2.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@ethersproject/abi': 5.8.0 + cbor2: 2.0.1 + ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@lit-protocol/vincent-scaffold-sdk@1.1.8(@lit-protocol/vincent-app-sdk@2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(@lit-protocol/vincent-tool-sdk@1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/node@22.18.12)(@types/react@19.0.12)(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@account-kit/infra': 4.62.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@account-kit/smart-contracts': 4.62.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@lit-protocol/contracts-sdk': 7.3.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@lit-protocol/vincent-app-sdk': 2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10) + '@lit-protocol/vincent-app-sdk': 2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@lit-protocol/vincent-tool-sdk': 1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@wagmi/core': 2.20.3(@types/react@19.0.12)(react@19.0.0)(typescript@5.8.2)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) chalk: 4.1.2 @@ -11461,7 +11576,7 @@ snapshots: esbuild: 0.19.12 esbuild-plugin-polyfill-node: 0.3.0(esbuild@0.19.12) ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - inquirer: 8.2.7(@types/node@20.17.28) + inquirer: 8.2.7(@types/node@22.18.12) ipfs-only-hash: 4.0.0 viem: 2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: @@ -11479,12 +11594,12 @@ snapshots: - utf-8-validate - zod - '@lit-protocol/vincent-scaffold-sdk@1.1.9-mma(@lit-protocol/vincent-app-sdk@2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10))(@lit-protocol/vincent-tool-sdk@1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/node@20.17.28)(@types/react@19.0.12)(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@lit-protocol/vincent-scaffold-sdk@1.1.9-mma(@lit-protocol/vincent-app-sdk@2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(@lit-protocol/vincent-tool-sdk@1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/node@22.18.12)(@types/react@19.0.12)(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@account-kit/infra': 4.62.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@account-kit/smart-contracts': 4.62.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@lit-protocol/contracts-sdk': 7.3.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@lit-protocol/vincent-app-sdk': 2.2.1(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10) + '@lit-protocol/vincent-app-sdk': 2.2.3(bufferutil@4.0.9)(react@19.0.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@lit-protocol/vincent-tool-sdk': 1.0.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@wagmi/core': 2.20.3(@types/react@19.0.12)(react@19.0.0)(typescript@5.8.2)(viem@2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)) chalk: 4.1.2 @@ -11492,7 +11607,7 @@ snapshots: esbuild: 0.19.12 esbuild-plugin-polyfill-node: 0.3.0(esbuild@0.19.12) ethers: 5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - inquirer: 8.2.7(@types/node@20.17.28) + inquirer: 8.2.7(@types/node@22.18.12) ipfs-only-hash: 4.0.0 viem: 2.37.5(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: @@ -12824,7 +12939,7 @@ snapshots: '@spruceid/siwe-parser@2.1.2': dependencies: - '@noble/hashes': 1.7.1 + '@noble/hashes': 1.8.0 apg-js: 4.4.0 uri-js: 4.4.1 valid-url: 1.0.9 @@ -13012,7 +13127,7 @@ snapshots: recast: 0.23.11 semver: 7.7.2 util: 0.12.5 - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: prettier: 3.5.3 transitivePeerDependencies: @@ -13241,7 +13356,7 @@ snapshots: '@trysound/sax@0.2.0': {} - '@tsconfig/node20@20.1.5': {} + '@tsconfig/node20@20.1.6': {} '@tybys/wasm-util@0.9.0': dependencies: @@ -13274,21 +13389,21 @@ snapshots: '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 20.17.28 + '@types/node': 22.18.12 '@types/brotli@1.3.4': dependencies: - '@types/node': 22.13.14 + '@types/node': 22.18.12 '@types/connect@3.4.38': dependencies: - '@types/node': 20.17.28 + '@types/node': 22.18.12 '@types/cookie@0.6.0': {} '@types/cors@2.8.17': dependencies: - '@types/node': 20.17.28 + '@types/node': 22.18.12 '@types/debug@4.1.12': dependencies: @@ -13302,7 +13417,7 @@ snapshots: '@types/express-serve-static-core@5.0.6': dependencies: - '@types/node': 20.17.28 + '@types/node': 22.18.12 '@types/qs': 6.9.18 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -13315,7 +13430,7 @@ snapshots: '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 22.13.14 + '@types/node': 22.18.12 '@types/http-errors@2.0.4': {} @@ -13340,7 +13455,7 @@ snapshots: '@types/keyv@3.1.4': dependencies: - '@types/node': 22.13.14 + '@types/node': 22.18.12 '@types/long@4.0.2': {} @@ -13358,11 +13473,11 @@ snapshots: '@types/mute-stream@0.0.4': dependencies: - '@types/node': 22.13.14 + '@types/node': 22.18.12 '@types/mysql@2.15.27': dependencies: - '@types/node': 22.13.14 + '@types/node': 22.18.12 '@types/node@12.20.55': optional: true @@ -13375,6 +13490,10 @@ snapshots: dependencies: undici-types: 6.20.0 + '@types/node@22.18.12': + dependencies: + undici-types: 6.21.0 + '@types/node@22.7.5': dependencies: undici-types: 6.19.8 @@ -13387,7 +13506,7 @@ snapshots: '@types/pg@8.15.5': dependencies: - '@types/node': 22.13.14 + '@types/node': 22.18.12 pg-protocol: 1.10.3 pg-types: 2.2.0 @@ -13407,19 +13526,19 @@ snapshots: '@types/responselike@1.0.3': dependencies: - '@types/node': 22.13.14 + '@types/node': 22.18.12 '@types/semver@7.7.0': {} '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 20.17.28 + '@types/node': 22.18.12 '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 20.17.28 + '@types/node': 22.18.12 '@types/send': 0.17.4 '@types/shimmer@1.2.0': {} @@ -13430,7 +13549,7 @@ snapshots: '@types/tedious@4.0.14': dependencies: - '@types/node': 22.13.14 + '@types/node': 22.18.12 '@types/tough-cookie@4.0.5': {} @@ -13455,12 +13574,12 @@ snapshots: '@types/ws@7.4.7': dependencies: - '@types/node': 22.13.14 + '@types/node': 22.18.12 optional: true '@types/ws@8.18.1': dependencies: - '@types/node': 22.13.14 + '@types/node': 22.18.12 optional: true '@types/yargs-parser@21.0.3': {} @@ -13750,7 +13869,7 @@ snapshots: tiny-invariant: 1.3.3 toformat: 2.0.0 - '@uniswap/smart-order-router@4.22.20(bufferutil@4.0.9)(hardhat@2.26.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(jsbi@3.2.5)(utf-8-validate@5.0.10)': + '@uniswap/smart-order-router@4.22.21(bufferutil@4.0.9)(hardhat@2.26.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10))(jsbi@3.2.5)(utf-8-validate@5.0.10)': dependencies: '@eth-optimism/sdk': 3.3.3(bufferutil@4.0.9)(ethers@5.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) '@types/brotli': 1.3.4 @@ -15181,13 +15300,13 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 - create-jest@29.7.0(@types/node@20.17.28): + create-jest@29.7.0(@types/node@22.18.12): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.17.28) + jest-config: 29.7.0(@types/node@22.18.12) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -15546,8 +15665,8 @@ snapshots: dependencies: '@ecies/ciphers': 0.2.3(@noble/ciphers@1.2.1) '@noble/ciphers': 1.2.1 - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 + '@noble/curves': 1.9.2 + '@noble/hashes': 1.8.0 ee-first@1.1.1: {} @@ -16842,9 +16961,9 @@ snapshots: ini@2.0.0: {} - inquirer@8.2.7(@types/node@20.17.28): + inquirer@8.2.7(@types/node@22.18.12): dependencies: - '@inquirer/external-editor': 1.0.1(@types/node@20.17.28) + '@inquirer/external-editor': 1.0.1(@types/node@22.18.12) ansi-escapes: 4.3.2 chalk: 4.1.2 cli-cursor: 3.1.0 @@ -17226,7 +17345,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.14 + '@types/node': 22.18.12 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.3 @@ -17246,16 +17365,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.17.28): + jest-cli@29.7.0(@types/node@22.18.12): dependencies: '@jest/core': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.17.28) + create-jest: 29.7.0(@types/node@22.18.12) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.17.28) + jest-config: 29.7.0(@types/node@22.18.12) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -17265,7 +17384,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@20.17.28): + jest-config@29.7.0(@types/node@22.18.12): dependencies: '@babel/core': 7.26.10 '@jest/test-sequencer': 29.7.0 @@ -17290,7 +17409,7 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.17.28 + '@types/node': 22.18.12 transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -17319,7 +17438,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.14 + '@types/node': 22.18.12 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -17329,7 +17448,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 20.17.28 + '@types/node': 22.18.12 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -17368,7 +17487,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.28 + '@types/node': 22.18.12 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -17403,7 +17522,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.28 + '@types/node': 22.18.12 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -17431,7 +17550,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.28 + '@types/node': 22.18.12 chalk: 4.1.2 cjs-module-lexer: 1.4.3 collect-v8-coverage: 1.0.2 @@ -17477,7 +17596,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.28 + '@types/node': 22.18.12 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -17496,7 +17615,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.17.28 + '@types/node': 22.18.12 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -17505,17 +17624,17 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 22.13.14 + '@types/node': 22.18.12 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.17.28): + jest@29.7.0(@types/node@22.18.12): dependencies: '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.17.28) + jest-cli: 29.7.0(@types/node@22.18.12) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -18900,7 +19019,7 @@ snapshots: '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 '@types/long': 4.0.2 - '@types/node': 22.13.14 + '@types/node': 22.18.12 long: 4.0.0 proxy-addr@2.0.7: @@ -19761,12 +19880,12 @@ snapshots: ts-dedent@2.2.0: {} - ts-jest@29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.19.12)(jest@29.7.0(@types/node@20.17.28))(typescript@5.8.2): + ts-jest@29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.19.12)(jest@29.7.0(@types/node@22.18.12))(typescript@5.8.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.28) + jest: 29.7.0(@types/node@22.18.12) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -19967,6 +20086,8 @@ snapshots: undici-types@6.20.0: {} + undici-types@6.21.0: {} + undici@5.29.0: dependencies: '@fastify/busboy': 2.1.1