Skip to content
Draft
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/fix-devnet-test-assertions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solana/web3-compat": patch
---

Fix flaky devnet integration test assertions for Base58 encoded string lengths
41 changes: 41 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,47 @@ jobs:
- name: Check bundle size limits
run: pnpm size-limit

devnet-integration:
name: Devnet Integration Tests
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.20.0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm

- name: Cache Turbo
uses: actions/cache@v4
with:
path: .turbo
key: ${{ runner.os }}-turbo-devnet-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-devnet-
${{ runner.os }}-turbo-

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build packages
run: pnpm build

- name: Run devnet integration tests
env:
TEST_PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }}
run: pnpm vitest run packages/web3-compat/test/devnet-integration.test.ts

changeset:
name: Require Changeset
runs-on: ubuntu-latest
Expand Down
2 changes: 0 additions & 2 deletions packages/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
Framework-agnostic building blocks for Solana RPC, subscriptions, wallets, and transactions. Works
in any runtime (React, Svelte, API routes, workers, etc.).

> **Status:** Experimental – expect rapid iteration.

## Install

```bash
Expand Down
279 changes: 165 additions & 114 deletions packages/web3-compat/README.md
Original file line number Diff line number Diff line change
@@ -1,168 +1,219 @@
# `@solana/web3-compat`
# @solana/web3-compat

Phase 0 of a backwards‑compatible surface that lets existing `@solana/web3.js`
code run on top of Kit primitives.
Drop-in replacement for `@solana/web3.js`. Same API, powered by `@solana/kit`.

This package is designed to help migrate from web3.js to Kit.
## Install

The goal of this release is **zero breaking changes** for applications that only
touch the subset of web3.js APIs listed below. There will be future releases that slowly
implement breaking changes as they move over to Kit primitives and intuitions.
```bash
npm install @solana/web3-compat
```

## Migrating from `@solana/web3.js`
## Quickstart

The migration process is straightforward and can be done incrementally:
Swap the import:

### Install the compatibility package
```ts
// Before
import { Connection, PublicKey, Keypair } from "@solana/web3.js";

```bash
pnpm add @solana/web3-compat
// After
import { Connection, PublicKey, Keypair } from "@solana/web3-compat";
```

Make sure you also have the required Kit peer dependencies:
That's it. Your existing code works as-is.

```bash
pnpm add @solana/kit @solana/client
```
## Common Solana flows (copy/paste)

### Update your imports
### Get balance

Replace your web3.js imports with the compatibility layer. Both import styles are supported:
```ts
import { Connection, PublicKey } from "@solana/web3-compat";

#### Named imports (TypeScript/ES6 style)
const connection = new Connection("https://api.devnet.solana.com");
const balance = await connection.getBalance(
new PublicKey("Fg6PaFpoGXkYsidMpWFKfwtz6DhFVyG4dL1x8kj7ZJup")
);
console.log(`Balance: ${balance / 1e9} SOL`);
```

**Before:**
### Get account info

```ts
import {
Connection,
Keypair,
PublicKey,
SystemProgram,
Transaction,
sendAndConfirmTransaction,
} from "@solana/web3.js";
const accountInfo = await connection.getAccountInfo(publicKey);
if (accountInfo) {
console.log("Lamports:", accountInfo.lamports);
console.log("Owner:", accountInfo.owner.toBase58());
console.log("Data length:", accountInfo.data.length);
}
```

**After:**
### Get latest blockhash

```ts
const { blockhash, lastValidBlockHeight } =
await connection.getLatestBlockhash();
console.log("Blockhash:", blockhash);
```

### Send transaction

```ts
import {
Connection,
Keypair,
PublicKey,
SystemProgram,
Transaction,
sendAndConfirmTransaction,
} from "@solana/web3-compat";
```

#### Namespace imports
const connection = new Connection("https://api.devnet.solana.com");
const sender = Keypair.generate();
const recipient = Keypair.generate();

**Before:**
const { blockhash } = await connection.getLatestBlockhash();

```js
const solanaWeb3 = require("@solana/web3.js");
const connection = new solanaWeb3.Connection(
"https://api.mainnet-beta.solana.com"
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: sender.publicKey,
toPubkey: recipient.publicKey,
lamports: 100_000_000, // 0.1 SOL
})
);
transaction.recentBlockhash = blockhash;
transaction.feePayer = sender.publicKey;
transaction.sign(sender);

const signature = await connection.sendRawTransaction(transaction.serialize());
console.log("Signature:", signature);
```

**After:**
### Confirm transaction

```js
const solanaWeb3 = require("@solana/web3-compat");
const connection = new solanaWeb3.Connection(
"https://api.mainnet-beta.solana.com"
```ts
// Simple confirmation
const result = await connection.confirmTransaction(signature, "confirmed");
console.log("Confirmed:", result.value?.err === null);

// With blockhash strategy
const result = await connection.confirmTransaction(
{ signature, blockhash, lastValidBlockHeight },
"confirmed"
);
```

Or with ES6 modules:
### Get program accounts

```ts
import * as solanaWeb3 from "@solana/web3-compat";
const TOKEN_PROGRAM = new PublicKey(
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
);

const accounts = await connection.getProgramAccounts(TOKEN_PROGRAM, {
filters: [{ dataSize: 165 }], // Token account size
});

accounts.forEach(({ pubkey, account }) => {
console.log("Address:", pubkey.toBase58());
console.log("Lamports:", account.lamports);
});
```

### (Optional): Leverage Kit features
### Request airdrop

You can gradually adopt Kit primitives alongside the compatibility layer using bridge helpers:
```ts
const signature = await connection.requestAirdrop(
publicKey,
1_000_000_000 // 1 SOL
);
await connection.confirmTransaction(signature);
console.log("Airdrop confirmed");
```

### Simulate transaction

```ts
import { toAddress, toPublicKey, toKitSigner } from "@solana/web3-compat";
const simulation = await connection.simulateTransaction(transaction);
console.log("Logs:", simulation.value.logs);
console.log("Error:", simulation.value.err);
```

// Convert between web3.js and Kit types
const web3PublicKey = new PublicKey("11111111111111111111111111111111");
const kitAddress = toAddress(web3PublicKey);
### Get token accounts

// Convert back if needed
const backToWeb3 = toPublicKey(kitAddress);
```ts
const tokenAccounts = await connection.getTokenAccountsByOwner(ownerPublicKey, {
programId: TOKEN_PROGRAM,
});

tokenAccounts.value.forEach(({ pubkey, account }) => {
console.log("Token account:", pubkey.toBase58());
});
```

### Migration checklist

- [ ] Install `@solana/web3-compat` and Kit dependencies
- [ ] Update import statements from `@solana/web3.js` to `@solana/web3-compat`
- [ ] Test your application
- [ ] Keep legacy `@solana/web3.js` for any unimplemented methods (see limitations below)

## Implemented in Phase 0

- `Connection` backed by Kit with support for:
- `getLatestBlockhash`
- `getBalance`
- `getAccountInfo`
- `getProgramAccounts`
- `getSignatureStatuses`
- `sendRawTransaction`
- `confirmTransaction`
- `simulateTransaction`
- Bridge helpers re-exported from `@solana/compat`:
- `toAddress`, `toPublicKey`, `toWeb3Instruction`, `toKitSigner`
- Programs:
- `SystemProgram.transfer` (manual u8/u64 little‑endian encoding)
- Utilities:
- `LAMPORTS_PER_SOL`
- `compileFromCompat`
- `sendAndConfirmTransaction`
- Re‑exports of all Web3 primitives (`PublicKey`, `Keypair`, `Transaction`,
`VersionedTransaction`, `TransactionInstruction`, etc)

## Running package locally

### Building the package
### WebSocket subscriptions

```bash
# Build TypeScript definitions
pnpm --filter @solana/web3-compat build
```ts
// Watch account changes
const subscriptionId = connection.onAccountChange(publicKey, (accountInfo) => {
console.log("Account updated:", accountInfo.lamports);
});

// Later: unsubscribe
await connection.removeAccountChangeListener(subscriptionId);

// Watch slot changes
const slotSubscription = connection.onSlotChange((slotInfo) => {
console.log("New slot:", slotInfo.slot);
});
```

## Migration to @solana/client

Access the underlying `SolanaClient` for gradual migration:

```ts
import { Connection } from "@solana/web3-compat";

const connection = new Connection("https://api.devnet.solana.com");

# Or build components separately
pnpm --filter @solana/web3-compat compile:js
pnpm --filter @solana/web3-compat compile:typedefs
// Get the SolanaClient instance
const client = connection.client;

// Use @solana/client features
await client.actions.connectWallet("phantom");
const wallet = client.store.getState().wallet;
if (wallet.status === "connected") {
console.log("Connected:", wallet.session.account.address);
}
```

### Running tests
## Bridge helpers

```bash
# Run all tests
pnpm --filter @solana/web3-compat test
Convert between web3.js and Kit types:

```ts
import {
toAddress,
toPublicKey,
toKitSigner,
toWeb3Instruction,
} from "@solana/web3-compat";

// web3.js PublicKey → Kit Address
const address = toAddress(publicKey);

// Kit Address → web3.js PublicKey
const pubkey = toPublicKey(address);

// web3.js Keypair → Kit Signer
const signer = toKitSigner(keypair);

// Kit Instruction → web3.js TransactionInstruction
const instruction = toWeb3Instruction(kitInstruction);
```

## Known limitations & edge cases

Phase 0 does not fully replace web3.js. Notable gaps:

- Only the Connection methods listed above are implemented. Any other Web3 call
(e.g. `getTransaction`, subscriptions, `requestAirdrop`) still needs the
legacy connection for now
- `getProgramAccounts` currently returns just the value array even when
`withContext: true` is supplied
- Account data is decoded from `base64` only. Other encodings such as
`jsonParsed` or `base64+zstd` are passed through to Kit but not post‑processed
- Numeric fields are coerced to JavaScript `number`s to match Web3 behaviour,
which means values above `Number.MAX_SAFE_INTEGER` will lose precision (which is how it
currently works)
- The compatibility layer does not yet try to normalise websocket connection
options or retry policies that web3.js exposes

Future phases will expand coverage and introduce intentional
breaking changes once users have an easy migration path.
## Notes

- Re-exports all `@solana/web3.js` types (`PublicKey`, `Keypair`, `Transaction`, etc.)
- Numeric fields coerced to `number` to match web3.js behavior
- `LAMPORTS_PER_SOL` and `sendAndConfirmTransaction` available as utilities

> **Future direction:** This package provides a migration path from `@solana/web3.js` to `@solana/kit`. Over time, more APIs will be deprecated in favor of Kit-native implementations. Use `connection.client` to gradually adopt `@solana/client` features.
Loading
Loading