@solana/web3.js
Connection for reads, Transaction/SystemProgram builders, Wallet Standard features for signing.
Legacy. @solana/web3.js v1 is in maintenance mode. For new apps, prefer
framework-kit (the recommended modern stack),
gill (ergonomic, for most apps), or
@solana/kit (low-level). This page is kept for apps still on v1.
butr discovers Solana Wallet Standard wallets and manages the connection.
@solana/web3.js provides Connection for chain reads and the
Transaction / SystemProgram builders; signing and sending go through the
wallet's own Wallet Standard features.
Get the wallet
import { useSelectedWallet, useSigner } from "@usebutr/react";
const wallet = useSelectedWallet("svm");
const signer = useSigner(wallet);
// `null` for a WalletConnect or Ledger wallet, which resolve another kind.
const walletStd = signer.data?.kind === "wallet-standard" ? signer.data.wallet : null;The snippets below run once wallet and walletStd are set.
Read chain state
import { Connection, PublicKey } from "@solana/web3.js";
const connection = new Connection("https://api.devnet.solana.com", "confirmed");
const publicKey = new PublicKey(wallet.account.walletAddress);
const lamports = await connection.getBalance(publicKey);Sign a message
getFeature reads the feature off the wallet, typed by the shape
@usebutr/svm exports; findAccount finds the Wallet Standard account for
butr's address:
import type { SolanaSignMessageFeature } from "@usebutr/svm";
import { findAccount, getFeature } from "@usebutr/wallet-standard-shared";
const feature = getFeature<SolanaSignMessageFeature>(
walletStd,
"solana:signMessage",
"signMessage",
);
const account = findAccount(walletStd.accounts, wallet.account.walletAddress);
if (feature === undefined || account === undefined) {
throw new Error("This wallet cannot sign messages for the active account");
}
const [output] = await feature.signMessage({ account, message });
// output.signature: Uint8Array; verify against output.signedMessageBuild and send a transaction
Build with @solana/web3.js, then submit through
solana:signAndSendTransaction. The chain input routes this one call to
devnet without moving the wallet:
import { SystemProgram, Transaction } from "@solana/web3.js";
import type { SolanaSignAndSendTransactionFeature } from "@usebutr/svm";
const { blockhash } = await connection.getLatestBlockhash();
const tx = new Transaction().add(
SystemProgram.transfer({ fromPubkey: publicKey, lamports: 0, toPubkey: BURN_ADDRESS }),
);
tx.recentBlockhash = blockhash;
tx.feePayer = publicKey;
const feature = getFeature<SolanaSignAndSendTransactionFeature>(
walletStd,
"solana:signAndSendTransaction",
"signAndSendTransaction",
);
const account = findAccount(walletStd.accounts, wallet.account.walletAddress);
if (feature === undefined || account === undefined) {
throw new Error("This wallet cannot send transactions for the active account");
}
const [output] = await feature.signAndSendTransaction({
account,
chain: "solana:devnet",
transaction: new Uint8Array(tx.serialize({ requireAllSignatures: false })),
});Wallets advertise Wallet Standard features unevenly, which is why getFeature can return
undefined. butr's adapter mirrors that: wallet.connector.sendTx and .signMessage exist only
when the wallet has the feature, so gate buttons on them.
Source: apps/demo-with-solana-web3js/src/app.tsx in the butr
repository.
Targets Solana devnet. Run pnpm dev --filter=demo-with-solana-web3js →
https://usebutr.demo-with-solana-web3js.localhost.