diff --git a/clients/js/package.json b/clients/js/package.json index de544e7..63499a4 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -52,7 +52,6 @@ "@solana-program/compute-budget": "^0.9.0", "@solana-program/system": "^0.8.0", "commander": "^13.0.0", - "p-limit": "^7.1.1", "pako": "^2.1.0", "picocolors": "^1.1.1", "yaml": "^2.7.0" diff --git a/clients/js/pnpm-lock.yaml b/clients/js/pnpm-lock.yaml index 7ae058b..2fcce25 100644 --- a/clients/js/pnpm-lock.yaml +++ b/clients/js/pnpm-lock.yaml @@ -20,9 +20,6 @@ importers: commander: specifier: ^13.0.0 version: 13.0.0 - p-limit: - specifier: ^7.1.1 - version: 7.1.1 pako: specifier: ^2.1.0 version: 2.1.0 @@ -1557,10 +1554,6 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-limit@7.1.1: - resolution: {integrity: sha512-i8PyM2JnsNChVSYWLr2BAjNoLi0BAYC+wecOnZnVV+YSNJkzP7cWmvI34dk0WArWfH9KwBHNoZI3P3MppImlIA==} - engines: {node: '>=20'} - p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} @@ -2008,10 +2001,6 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yocto-queue@1.2.1: - resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} - engines: {node: '>=12.20'} - snapshots: '@ava/typescript@4.1.0': @@ -3562,10 +3551,6 @@ snapshots: dependencies: yocto-queue: 0.1.0 - p-limit@7.1.1: - dependencies: - yocto-queue: 1.2.1 - p-locate@5.0.0: dependencies: p-limit: 3.1.0 @@ -3956,5 +3941,3 @@ snapshots: yargs-parser: 21.1.1 yocto-queue@0.1.0: {} - - yocto-queue@1.2.1: {} diff --git a/clients/js/src/internals.ts b/clients/js/src/internals.ts index 5f254d8..071212c 100644 --- a/clients/js/src/internals.ts +++ b/clients/js/src/internals.ts @@ -24,7 +24,6 @@ import { TransactionPlanner, TransactionSigner, } from '@solana/kit'; -import { limitFunction } from 'p-limit'; import { findMetadataPda, SeedArgs } from './generated'; import { getProgramAuthority } from './utils'; @@ -88,25 +87,22 @@ export function createDefaultTransactionPlannerAndExecutor(input: { }); const executor = createTransactionPlanExecutor({ - executeTransactionMessage: limitFunction( - async (message, config) => { - const { value: latestBlockhash } = await input.rpc - .getLatestBlockhash() - .send(); - const transaction = await pipe( - setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, message), - async (m) => await estimateAndSetCULimit(m, config), - async (m) => await signTransactionMessageWithSigners(await m, config) - ); - assertIsSendableTransaction(transaction); - await sendAndConfirmTransaction(transaction, { - ...config, - commitment: 'confirmed', - }); - return { transaction }; - }, - { concurrency: input.concurrency ?? 5 } - ), + executeTransactionMessage: limitFunction(async (message, config) => { + const { value: latestBlockhash } = await input.rpc + .getLatestBlockhash() + .send(); + const transaction = await pipe( + setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, message), + async (m) => await estimateAndSetCULimit(m, config), + async (m) => await signTransactionMessageWithSigners(await m, config) + ); + assertIsSendableTransaction(transaction); + await sendAndConfirmTransaction(transaction, { + ...config, + commitment: 'confirmed', + }); + return { transaction }; + }, input.concurrency ?? 5), }); return { planner, executor }; @@ -123,3 +119,39 @@ export async function isValidInstructionPlan( return false; } } + +function limitFunction( + fn: (...args: TArguments) => PromiseLike, + concurrency: number +): (...args: TArguments) => Promise { + let running = 0; + const queue: Array<{ + args: TArguments; + resolve: (value: TReturnType) => void; + reject: (reason?: unknown) => void; + }> = []; + + function process() { + // Do nothing if we're still running at max concurrency + // or if there's nothing left to process. + if (running >= concurrency || queue.length === 0) return; + + running++; + const { args, resolve, reject } = queue.shift()!; + + Promise.resolve(fn(...args)) + .then(resolve) + .catch(reject) + .finally(() => { + running--; + process(); + }); + } + + return function (...args) { + return new Promise((resolve, reject) => { + queue.push({ args, resolve, reject }); + process(); + }); + }; +}