Skip to content

clients-js: Bump kit deps#577

Merged
joncinque merged 2 commits intosolana-program:mainfrom
joncinque:bump-kit
Mar 26, 2026
Merged

clients-js: Bump kit deps#577
joncinque merged 2 commits intosolana-program:mainfrom
joncinque:bump-kit

Conversation

@joncinque
Copy link
Copy Markdown
Contributor

Problem

The kit deps on the js package are old.

Summary of changes

Bump the kit deps to the newest. While doing this, I ran into some changed types, and I tried my hand at pipe, but I had to do some ugly things to make it work.

Let me know what I should change!

@joncinque joncinque requested a review from lorisleiva March 25, 2026 17:27
#### Problem

The kit deps on the js package are old.

#### Summary of changes

Bump the kit deps to the newest. While doing this, I ran into some
changed types, and I tried my hand at `pipe`, but I had to do some ugly
things to make it work.
lorisleiva
lorisleiva previously approved these changes Mar 26, 2026
Copy link
Copy Markdown
Member

@lorisleiva lorisleiva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I think it's good as-is but offered an alternative using instruction plans.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be Rpc<GetMinimumBalanceForRentExemptionApi & GetStakeMinimumDelegationApi> instead of any.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like this whole method would be better suited as an instruction plan factory. It would look something like:

export async function getInitializeInstructionPlan(
  rpc: Rpc<GetMinimumBalanceForRentExemptionApi & GetStakeMinimumDelegationApi>,
  voteAccount: VoteAccountAddress,
  payer: Address,
  skipMetadata = false
): Promise<InstructionPlan> {
  const pool = await findPoolAddress(SINGLE_POOL_PROGRAM_ID, voteAccount);
  const [stake, mint, onramp, poolRent, stakeRent, mintRent, minimumDelegationObj, initializePool, initializeOnRamp] =
    await Promise.all([
      findPoolStakeAddress(SINGLE_POOL_PROGRAM_ID, pool),
      findPoolMintAddress(SINGLE_POOL_PROGRAM_ID, pool),
      findPoolOnRampAddress(SINGLE_POOL_PROGRAM_ID, pool),
      rpc.getMinimumBalanceForRentExemption(SINGLE_POOL_ACCOUNT_SIZE).send(),
      rpc.getMinimumBalanceForRentExemption(STAKE_ACCOUNT_SIZE).send(),
      rpc.getMinimumBalanceForRentExemption(MINT_SIZE).send(),
      rpc.getStakeMinimumDelegation().send(),
      initializePoolInstruction(voteAccount),
      initializeOnRampInstruction(pool),
    ]);
  const lamportsPerSol = 1_000_000_000n;
  const minimumPoolBalance =
    minimumDelegationObj.value > lamportsPerSol ? minimumDelegationObj.value : lamportsPerSol;

  return sequentialInstructionPlan([
    parallelInstructionPlan([
      SystemInstruction.transfer({ from: payer, to: pool, lamports: poolRent }),
      SystemInstruction.transfer({ from: payer, to: stake, lamports: stakeRent + minimumPoolBalance }),
      SystemInstruction.transfer({ from: payer, to: onramp, lamports: stakeRent }),
      SystemInstruction.transfer({ from: payer, to: mint, lamports: mintRent }),
    ]),
    initializePool,
    initializeOnRamp,
    ...(skipMetadata ? [] : [await createTokenMetadataInstruction(pool, payer)])
  ]);
}

That way you defer the transaction creation to the end user. If you still wanted to provide a ready-made transaction though you could still offer initializeTransaction such that it delegates to getInitializeInstructionPlan. Something like:

export async function getInitializeInstructionPlan(
  rpc: Rpc<GetMinimumBalanceForRentExemptionApi & GetStakeMinimumDelegationApi>,
  voteAccount: VoteAccountAddress,
  payer: Address,
  skipMetadata = false
): Promise<TransactionMessage> {
  const transactionPlanner = createTransactionPlanner({
    createTransactionMessage: () => pipe(
      createTransactionMessage({ version: 0 }),
      m => setTransactionMessageFeePayer(payer, m),
    )
  });

  const instructionPlan = await getInitializeInstructionPlan(rpc, voteAccount, payer, skipMetadata);
  const transactionPlan = await transactionPlanner(instructionPlan);
  assertIsSingleTransactionPlan(transactionPlan);
  return transactionPlan.message;
}

But I would recommend letting the end user construct its own transaction. With Kit plugins, they would be able to do same simply by running:

const instructionPlan = await getInitializeInstructionPlan(rpc, voteAccount, payer, skipMetadata);
const message = await client.planTransaction(instructionPlan);

// Or they could send it directly like so:
const result = await client.sendTransaction(instructionPlan);

@joncinque
Copy link
Copy Markdown
Contributor Author

Thanks for the lesson! It was easy to integrate all of that in the clients/js, but I wasn't sure how to declare the return types for the Connection wrapper in clients/js-legacy since things like GetAccountInfoApiResponse are private

@lorisleiva
Copy link
Copy Markdown
Member

Ah yeah I didn't notice you had an RPC wrapper on the legacy package. I think you should be able to cast the whole returned object like return { ... } as Rpc<...> but the current solution is also fine since the any types are only internal anyway.

@joncinque
Copy link
Copy Markdown
Contributor Author

I think you should be able to cast the whole returned object like return { ... } as Rpc<...>

Thanks for the suggestion, but it doesn't work unfortunately

Copy link
Copy Markdown
Member

@lorisleiva lorisleiva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nevermind then. The function signatures must not be quite compatible enough for TypeScript to be happy. ☺️

@joncinque joncinque merged commit 6113f28 into solana-program:main Mar 26, 2026
22 checks passed
@joncinque joncinque deleted the bump-kit branch March 26, 2026 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants