Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/metal-hands-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@solana/kit-plugin-rpc': minor
---

Add `solanaRpc`, `solanaMainnetRpc`, `solanaDevnetRpc`, and `solanaLocalRpc` all-in-one plugins with `SolanaRpcConfig` configuration type.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,12 @@ _Do you know any? Please open a PR to add them here!_

This repo provides the following individual plugin packages. You can learn more about each package by following the links to their READMEs below.

| Package | Version | Description | Plugins |
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`@solana/kit-plugin-rpc`](./packages/kit-plugin-rpc) | [![npm](https://img.shields.io/npm/v/@solana/kit-plugin-rpc.svg?style=flat)](https://www.npmjs.com/package/@solana/kit-plugin-rpc) | Connect to Solana clusters | `rpcConnection`, `rpcSubscriptionsConnection`, `solanaRpcConnection`, `solanaRpcSubscriptionsConnection`, `rpcAirdrop`, `rpcGetMinimumBalance`, `rpcTransactionPlanner`, `rpcTransactionPlanExecutor` |
| [`@solana/kit-plugin-payer`](./packages/kit-plugin-payer) | [![npm](https://img.shields.io/npm/v/@solana/kit-plugin-payer.svg?style=flat)](https://www.npmjs.com/package/@solana/kit-plugin-payer) | Manage transaction fee payers | `payer`, `payerFromFile`, `generatedPayer`, `generatedPayerWithSol` |
| [`@solana/kit-plugin-litesvm`](./packages/kit-plugin-litesvm) | [![npm](https://img.shields.io/npm/v/@solana/kit-plugin-litesvm.svg?style=flat)](https://www.npmjs.com/package/@solana/kit-plugin-litesvm) | LiteSVM support | `litesvm`, `litesvmAirdrop`, `litesvmGetMinimumBalance`, `litesvmTransactionPlanner`, `litesvmTransactionPlanExecutor` |
| [`@solana/kit-plugin-instruction-plan`](./packages/kit-plugin-instruction-plan) | [![npm](https://img.shields.io/npm/v/@solana/kit-plugin-instruction-plan.svg?style=flat)](https://www.npmjs.com/package/@solana/kit-plugin-instruction-plan) | Transaction planning and execution | `transactionPlanner`, `transactionPlanExecutor`, `planAndSendTransactions` |
| Package | Version | Description | Plugins |
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`@solana/kit-plugin-rpc`](./packages/kit-plugin-rpc) | [![npm](https://img.shields.io/npm/v/@solana/kit-plugin-rpc.svg?style=flat)](https://www.npmjs.com/package/@solana/kit-plugin-rpc) | Connect to Solana clusters | `solanaRpc`, `solanaMainnetRpc`, `solanaDevnetRpc`, `solanaLocalRpc`, `rpcConnection`, `rpcSubscriptionsConnection`, `solanaRpcConnection`, `solanaRpcSubscriptionsConnection`, `rpcAirdrop`, `rpcGetMinimumBalance`, `rpcTransactionPlanner`, `rpcTransactionPlanExecutor` |
| [`@solana/kit-plugin-payer`](./packages/kit-plugin-payer) | [![npm](https://img.shields.io/npm/v/@solana/kit-plugin-payer.svg?style=flat)](https://www.npmjs.com/package/@solana/kit-plugin-payer) | Manage transaction fee payers | `payer`, `payerFromFile`, `generatedPayer`, `generatedPayerWithSol` |
| [`@solana/kit-plugin-litesvm`](./packages/kit-plugin-litesvm) | [![npm](https://img.shields.io/npm/v/@solana/kit-plugin-litesvm.svg?style=flat)](https://www.npmjs.com/package/@solana/kit-plugin-litesvm) | LiteSVM support | `litesvm`, `litesvmAirdrop`, `litesvmGetMinimumBalance`, `litesvmTransactionPlanner`, `litesvmTransactionPlanExecutor` |
| [`@solana/kit-plugin-instruction-plan`](./packages/kit-plugin-instruction-plan) | [![npm](https://img.shields.io/npm/v/@solana/kit-plugin-instruction-plan.svg?style=flat)](https://www.npmjs.com/package/@solana/kit-plugin-instruction-plan) | Transaction planning and execution | `transactionPlanner`, `transactionPlanExecutor`, `planAndSendTransactions` |

## Community Plugins

Expand Down
105 changes: 105 additions & 0 deletions packages/kit-plugin-rpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,111 @@ This package provides plugins that add RPC functionality to your Kit clients.
pnpm install @solana/kit-plugin-rpc
```

## `solanaRpc` plugin

The `solanaRpc` plugin sets up a full Solana RPC client in a single call. It installs an RPC connection, RPC Subscriptions, minimum balance computation, transaction planning, and transaction execution on the client.

The client must have a `payer` set before applying this plugin.

### Installation

```ts
import { createClient } from '@solana/kit';
import { solanaRpc } from '@solana/kit-plugin-rpc';
import { payer } from '@solana/kit-plugin-payer';

const client = createClient()
.use(payer(myPayer))
.use(solanaRpc({ rpcUrl: 'https://api.mainnet-beta.solana.com' }));
```

### Options

All options are provided via a `SolanaRpcConfig` object:

- `rpcUrl` **(required)**: URL of the Solana RPC endpoint.
- `rpcSubscriptionsUrl`: URL of the RPC Subscriptions endpoint. Defaults to the `rpcUrl` with the protocol changed from `http` to `ws`.
- `rpcConfig`: Optional configuration forwarded to `createSolanaRpc`.
- `rpcSubscriptionsConfig`: Optional configuration forwarded to `createSolanaRpcSubscriptions`.
- `priorityFees`: Priority fees in micro-lamports per compute unit. Defaults to no priority fees.
- `maxConcurrency`: Maximum number of concurrent transaction executions. Defaults to 10.
- `skipPreflight`: Whether to always skip preflight simulation. Defaults to `false`.

### Features

- `rpc`: Call any Solana RPC method.
- `rpcSubscriptions`: Subscribe to Solana RPC notifications.
- `getMinimumBalance`: Compute minimum lamports for rent exemption.
- `transactionPlanner`: Plan instructions into transaction messages.
- `transactionPlanExecutor`: Sign and send planned transactions.
- `sendTransaction(s)` / `planTransaction(s)`: Convenience helpers that combine planning and execution.

## `solanaMainnetRpc` plugin

A convenience wrapper around `solanaRpc` that types the connection as a mainnet URL, preventing accidental use of devnet-only features such as airdrops.

### Installation

```ts
import { createClient } from '@solana/kit';
import { solanaMainnetRpc } from '@solana/kit-plugin-rpc';
import { payer } from '@solana/kit-plugin-payer';

const client = createClient()
.use(payer(myPayer))
.use(solanaMainnetRpc({ rpcUrl: 'https://api.mainnet-beta.solana.com' }));
```

### Features

_See `solanaRpc` for available features._

## `solanaDevnetRpc` plugin

A convenience wrapper around `solanaRpc` that defaults to the public devnet endpoint (`https://api.devnet.solana.com`) and includes airdrop support for requesting SOL from the faucet.

### Installation

```ts
import { createClient } from '@solana/kit';
import { solanaDevnetRpc } from '@solana/kit-plugin-rpc';
import { payerFromFile } from '@solana/kit-plugin-payer';

const client = createClient().use(payerFromFile('~/.config/solana/id.json')).use(solanaDevnetRpc());
```

### Features

_See `solanaRpc` for available features, plus:_

- `airdrop`: Request SOL from the devnet faucet.
```ts
await client.airdrop(address('HQVxiMVDoV9jzG4tpoxmDZsNfWvaHXm8DGGv93Gka75v'), lamports(1_000_000_000n));
```

## `solanaLocalRpc` plugin

A convenience wrapper around `solanaRpc` that defaults to `http://127.0.0.1:8899` for the RPC and `ws://127.0.0.1:8900` for subscriptions, and includes airdrop support.

### Installation

```ts
import { createClient } from '@solana/kit';
import { solanaLocalRpc } from '@solana/kit-plugin-rpc';
import { payerFromFile } from '@solana/kit-plugin-payer';

const client = createClient().use(payerFromFile('~/.config/solana/id.json')).use(solanaLocalRpc());
```

### Features

_See `solanaRpc` for available features, plus:_

- `airdrop`: Request SOL from the local validator faucet.
```ts
await client.airdrop(address('HQVxiMVDoV9jzG4tpoxmDZsNfWvaHXm8DGGv93Gka75v'), lamports(1_000_000_000n));
```

## `rpcConnection` plugin

The `rpcConnection` plugin sets a provided `Rpc` instance on the client. This is the generic variant that works with any RPC API.
Expand Down
3 changes: 3 additions & 0 deletions packages/kit-plugin-rpc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
"peerDependencies": {
"@solana/kit": "^6.8.0"
},
"dependencies": {
"@solana/kit-plugin-instruction-plan": "workspace:*"
},
"license": "MIT",
"repository": {
"type": "git",
Expand Down
203 changes: 203 additions & 0 deletions packages/kit-plugin-rpc/src/solana-rpc.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,215 @@
import {
ClientWithPayer,
ClusterUrl,
createSolanaRpc,
createSolanaRpcSubscriptions,
DefaultRpcSubscriptionsChannelConfig,
DevnetUrl,
extendClient,
MainnetUrl,
MicroLamports,
pipe,
} from '@solana/kit';
import { planAndSendTransactions } from '@solana/kit-plugin-instruction-plan';

import { rpcAirdrop } from './airdrop';
import { rpcGetMinimumBalance } from './get-minimum-balance';
import { rpcConnection, rpcSubscriptionsConnection } from './rpc';
import { rpcTransactionPlanExecutor } from './transaction-plan-executor';
import { rpcTransactionPlanner } from './transaction-planner';

/**
* Configuration for the Solana RPC plugins.
*
* @typeParam TClusterUrl - The type of the RPC endpoint URL.
*/
export type SolanaRpcConfig<TClusterUrl extends ClusterUrl = ClusterUrl> = {
/**
* The maximum number of concurrent transaction executions allowed.
* Defaults to 10.
*/
maxConcurrency?: number;
/**
* The priority fees to set on transactions in micro-lamports per compute unit.
* Defaults to no priority fees.
*/
priorityFees?: MicroLamports;
/** Optional configuration forwarded to {@link createSolanaRpc}. */
rpcConfig?: Parameters<typeof createSolanaRpc>[1];
/** Optional configuration forwarded to {@link createSolanaRpcSubscriptions}. */
rpcSubscriptionsConfig?: Parameters<typeof createSolanaRpcSubscriptions>[1];
/**
* URL of the Solana RPC Subscriptions endpoint.
* Defaults to the `rpcUrl` with the protocol changed from `http` to `ws`.
*/
rpcSubscriptionsUrl?: TClusterUrl;
/** URL of the Solana RPC endpoint. */
rpcUrl: TClusterUrl;
/**
* Whether to skip the preflight simulation when sending transactions.
*
* When `false` (default), preflight is skipped only if a compute unit
* estimation simulation was already performed for that transaction.
*
* When `true`, preflight is always skipped and the transaction is sent
* directly to the validator.
*
* Defaults to `false`.
*/
skipPreflight?: boolean;
};

/**
* Enhances a client with a full Solana RPC setup including RPC connection,
* RPC Subscriptions, minimum balance computation, transaction planning, and
* transaction execution.
*
* The client must have a `payer` set before applying this plugin.
*
* @param config - Configuration for the Solana RPC connection.
* @return A plugin that adds `client.rpc`, `client.rpcSubscriptions`,
* `client.getMinimumBalance`, `client.transactionPlanner`,
* `client.transactionPlanExecutor`, and `client.sendTransactions`.
*
* @example
* ```ts
* import { createClient } from '@solana/kit';
* import { solanaRpc } from '@solana/kit-plugin-rpc';
* import { payer } from '@solana/kit-plugin-payer';
*
* const client = createClient()
* .use(payer(myPayer))
* .use(solanaRpc({ rpcUrl: 'https://api.mainnet-beta.solana.com' }));
* ```
*
* @see {@link solanaMainnetRpc}
* @see {@link solanaDevnetRpc}
* @see {@link solanaLocalRpc}
*/
export function solanaRpc<TClusterUrl extends ClusterUrl>(config: SolanaRpcConfig<TClusterUrl>) {
return <T extends ClientWithPayer>(client: T) =>
pipe(
client,
solanaRpcConnection<TClusterUrl>(config.rpcUrl, config.rpcConfig),
solanaRpcSubscriptionsConnection<TClusterUrl>(
Comment on lines +91 to +94
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 didn't realise you could use pipe to compose plugins like this, that's really nice!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah createClient is just a fancy pipe. In fact I tried using createClient first here but it made the types way more complicated than they need to be (because of the async conditionals) so I thought it'd make more sense to stick to pipes for internal plugin compositions.

config.rpcSubscriptionsUrl ?? (config.rpcUrl.replace(/^http/, 'ws') as TClusterUrl),
config.rpcSubscriptionsConfig,
Comment thread
lorisleiva marked this conversation as resolved.
),
rpcGetMinimumBalance(),
rpcTransactionPlanner({ priorityFees: config.priorityFees }),
rpcTransactionPlanExecutor({ maxConcurrency: config.maxConcurrency, skipPreflight: config.skipPreflight }),
planAndSendTransactions(),
);
}

/**
* Enhances a client with a full Solana mainnet RPC setup.
*
* This is a convenience wrapper around {@link solanaRpc} that types the
* connection as a mainnet URL, preventing accidental use of devnet-only
* features such as airdrops.
*
* @param config - Configuration for the Solana RPC connection.
* @return A plugin that applies {@link solanaRpc} with a mainnet URL type.
*
* @example
* ```ts
* import { createClient } from '@solana/kit';
* import { solanaMainnetRpc } from '@solana/kit-plugin-rpc';
* import { payer } from '@solana/kit-plugin-payer';
*
* const client = createClient()
* .use(payer(myPayer))
* .use(solanaMainnetRpc({ rpcUrl: 'https://api.mainnet-beta.solana.com' }));
* ```
*
* @see {@link solanaRpc}
* @see {@link solanaDevnetRpc}
Comment thread
lorisleiva marked this conversation as resolved.
* @see {@link solanaLocalRpc}
*/
export function solanaMainnetRpc(config: SolanaRpcConfig<string>) {
return <T extends ClientWithPayer>(client: T) =>
pipe(client, solanaRpc<MainnetUrl>(config as SolanaRpcConfig<MainnetUrl>));
}

/**
* Enhances a client with a full Solana devnet RPC setup.
*
* This is a convenience wrapper around {@link solanaRpc} that defaults to
* the public devnet endpoint and includes {@link rpcAirdrop} for requesting
* SOL from the faucet.
*
* @param config - Optional configuration overrides. Defaults `rpcUrl` to
* `https://api.devnet.solana.com`.
* @return A plugin that applies {@link solanaRpc} with a devnet URL type
* and airdrop support.
*
* @example
* ```ts
* import { createClient } from '@solana/kit';
* import { solanaDevnetRpc } from '@solana/kit-plugin-rpc';
* import { payerFromFile } from '@solana/kit-plugin-payer';
*
* const client = createClient()
* .use(payerFromFile("~/.config/solana/id.json"))
* .use(solanaDevnetRpc());
* ```
*
* @see {@link solanaRpc}
* @see {@link solanaMainnetRpc}
* @see {@link solanaLocalRpc}
*/
export function solanaDevnetRpc(config?: Partial<SolanaRpcConfig<string>>) {
return <T extends ClientWithPayer>(client: T) =>
pipe(
client,
solanaRpc<DevnetUrl>({
...config,
rpcUrl: config?.rpcUrl ?? 'https://api.devnet.solana.com',
} as SolanaRpcConfig<DevnetUrl>),
rpcAirdrop(),
);
}

/**
* Enhances a client with a full Solana local validator RPC setup.
*
* This is a convenience wrapper around {@link solanaRpc} that defaults to
* `http://127.0.0.1:8899` for the RPC and `ws://127.0.0.1:8900` for
* subscriptions, and includes {@link rpcAirdrop} for requesting SOL from
* the faucet.
*
* @param config - Optional configuration overrides.
* @return A plugin that applies {@link solanaRpc} with localhost defaults
* and airdrop support.
*
* @example
* ```ts
* import { createClient } from '@solana/kit';
* import { solanaLocalRpc } from '@solana/kit-plugin-rpc';
* import { payerFromFile } from '@solana/kit-plugin-payer';
*
* const client = createClient()
* .use(payerFromFile("~/.config/solana/id.json"))
* .use(solanaLocalRpc());
* ```
*
* @see {@link solanaRpc}
* @see {@link solanaMainnetRpc}
* @see {@link solanaDevnetRpc}
*/
export function solanaLocalRpc(config?: Partial<SolanaRpcConfig<string>>) {
return <T extends ClientWithPayer>(client: T) =>
pipe(
client,
solanaRpc({
...config,
rpcSubscriptionsUrl: config?.rpcSubscriptionsUrl ?? 'ws://127.0.0.1:8900',
rpcUrl: config?.rpcUrl ?? 'http://127.0.0.1:8899',
}),
rpcAirdrop(),
);
}

/**
* Enhances a client with a Solana RPC connection created from a cluster URL.
Expand Down
Loading
Loading