butr
Integrations

gill

The ergonomic SDK on top of @solana/kit, the path the Solana Foundation recommends for most apps.

gill wraps @solana/kit with friendlier client and transaction builders. It is the path the Solana Foundation recommends for most app developers writing RPC and transaction code. butr owns the wallet; gill owns the RPC and the transaction builder; the wallet's Wallet Standard features own signing.

Get the wallet and read state

The wallet and its Wallet Standard handle, walletStd, come from butr exactly as in the @solana/kit integration; the snippets below run once both are set. createSolanaClient resolves a moniker to an RPC endpoint:

import { address, createSolanaClient } from "gill";

const { rpc } = createSolanaClient({ urlOrMoniker: "devnet" });

const addr = address(wallet.account.walletAddress);
const { value } = await rpc.getBalance(addr).send();
const sol = `${Number(value) / 1_000_000_000} SOL`;

Build and send a transaction

The wallet signs, not gill, so the fee payer is a no-op signer over butr's connected address. gill's program helpers stay fully typed; compile to wire bytes and hand them to solana:signAndSendTransaction:

import { base64ToBytes, bytesToBase58 } from "@usebutr/core";
import type { SolanaSignAndSendTransactionFeature } from "@usebutr/svm";
import { findAccount, getFeature } from "@usebutr/wallet-standard-shared";
import {
  compileTransaction,
  createNoopSigner,
  createTransaction,
  getBase64EncodedWireTransaction,
} from "gill";
import { getTransferSolInstruction } from "gill/programs";

const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const feePayer = createNoopSigner(addr);
const tx = createTransaction({
  feePayer,
  instructions: [
    getTransferSolInstruction({ amount: 0, destination: BURN_ADDRESS, source: feePayer }),
  ],
  latestBlockhash,
  version: 0,
});
const transaction = base64ToBytes(getBase64EncodedWireTransaction(compileTransaction(tx)));

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,
});
const signature = output === undefined ? null : bytesToBase58(output.signature);

Message signing uses solana:signMessage exactly as in the @solana/kit integration. For a shorter path through butr's adapter, wallet.connector.sendTx(transaction, { chain: SVM_CHAINS.devnet }) does the same when the wallet defines it.

gill re-exports @solana/kit, so kit primitives (createNoopSigner, compileTransaction, getBase64EncodedWireTransaction) come from the same gill entry point; you do not need a separate @solana/kit dependency.

Source: apps/demo-with-gill/src/app.tsx in the butr repository. Targets Solana devnet. Run pnpm dev --filter=demo-with-gill → https://usebutr.demo-with-gill.localhost.