@solana/kit
v7.1.0 (2026-08-14)
Minor Changes
-
[
@solana/errors,@solana/kit,@solana/react,@solana/subscribable] #18117022c26Thanks @mcintyre94! - AddbridgeStoreToAsyncIterableto@solana/subscribablebridgeStoreToAsyncIterableadapts aReactiveStreamStoreinto the pull-basedAsyncIterablecontract that consumers like TanStack Query'sexperimental_streamedQueryexpect. It is now a public export of@solana/subscribable(and re-exported from@solana/kit). It was previously an internal helper of@solana/react, but it is not React- or TanStack-specific and is useful to any consumer that needs to drive a stream store byfor await-ing it.The bridge only observes the store — consistent with the rest of the ecosystem, the caller owns the store's lifecycle (
connect()it yourself, bound to the same signal, andreset()it when done). The bridge subscribes, seeds from the store's current snapshot, yields values, and unsubscribes when iteration ends.It throws the new
SOLANA_ERROR__SUBSCRIBABLE__STREAM_CLOSED_WITHOUT_ERRORwhen a store closes in an error state with a nullish payload. This is the erroruseSubscriptionQueryanduseTrackedDataQuerynow surface in that case; the SWR bridge is unaffected. -
[
@solana/errors,@solana/offchain-messages] #188814a3e5bThanks @mcintyre94! - Add anassertOffchainMessageV1Equalhelper that asserts that a version 1 offchain message you received from an untrusted signer (eg. a wallet) is the message you expected it to sign. Verifying a signature proves only that the signer produced it over the bytes it handed back, not that those bytes represent the message you asked for, so assert this before verifying signatures withverifyOffchainMessageEnvelope. The helper compares the content and the required signatories, and reports each kind of mismatch with its own error code: the newSOLANA_ERROR__OFFCHAIN_MESSAGE__CONTENT_DOES_NOT_MATCH_EXPECTEDandSOLANA_ERROR__OFFCHAIN_MESSAGE__REQUIRED_SIGNATORIES_DO_NOT_MATCH_EXPECTED. Required signatories are compared without regard to order, since a decoded message lists them in the order the specification mandates while yours may be in any order. It accepts anOffchainMessageV1rather than theOffchainMessageunion that decoding produces, so narrow the decoded message to a version 1 message before calling it. -
[
@solana/instruction-plans] #19159e7daeaThanks @mcintyre94! - Let thecreateTransactionPlanExecutorcallback return the context of a successful resultThe
executeTransactionMessagecallback may now return the context that a successful result should carry, instead of aSignatureor aTransaction. When it does, that context is used as-is: nothing is derived from it, and in particulargetSignatureFromTransactionis never called on your behalf.const transactionPlanExecutor = createTransactionPlanExecutor({ executeTransactionMessage: async (context, message) => { const transaction = await signTransactionMessageWithSigners(message); context.transaction = transaction; + const signature = getSignatureFromTransaction(transaction); await sendAndConfirmTransaction(transaction, { commitment: 'confirmed' }); - return transaction; + return { signature, transaction }; }, });Since a successful result always carries a signature, a returned context must include one — a callback that declares a custom context and forgets a property of it now fails to compile, rather than producing a result whose context is typed but
undefinedat runtime. That signature is also how the executor tells a returned context apart from a returnedTransaction, which keeps its signatures in asignaturesmap and therefore never has one.The mutable
contextargument is unchanged and still serves the failure path: whatever the callback stores on it before it throws is preserved in the resultingFailedSingleTransactionPlanResult. On success the two are merged, with the returned context taking precedence, so a property stored but not returned is still reported.Returning a
Signatureor aTransactionis deprecated. Both still behave exactly as before — a returned signature is stored ascontext.signature, and a returned transaction is stored ascontext.transactionwith its signature derived from it — and IDEs now flag those call sites, becausecreateTransactionPlanExecutorgained a deprecated overload that only matches callbacks returning those types. Note that a config declared asTransactionPlanExecutorConfigup front is not flagged, since that type permits either return style.Prefer returning a context, since deriving a signature from a transaction throws
SOLANA_ERROR__TRANSACTION__FEE_PAYER_SIGNATURE_MISSINGwhen the fee payer slot is empty. An executor that deliberately produces partially signed transactions — signed by an authority, to be paid for and submitted by a relayer later — can now succeed by returning its own signature alongside the transaction. Dropping the signature from a successful result's context altogether remains impossible, sinceSuccessfulSingleTransactionPlanResultguarantees one.Failure handling is unchanged, including the signature still derived from a
transactionleft on the context when the callback throws. Since the callback never returned anything in that case, there is nothing to bypass that derivation, so a callback working with fee-payer-unsigned transactions should avoid storing them on the context — otherwise deriving a signature from one replaces the error it meant to report. -
[
@solana/kit] #18984a5f717Thanks @lorisleiva! - Add helpers to create client interfaces from a rawRpcAdd
createClientWithGetMinimumBalanceFromRpc,createClientWithFetchAccountsFromRpcandcreateClientWithInterfacesFromRpcto@solana/kit. These convenience helpers let consumers that only have a rawRpcobject construct the corresponding client interfaces (ClientWithGetMinimumBalanceandClientWithFetchAccounts) without assembling a full Kit client.createClientWithInterfacesFromRpcfills in whichever interfaces the RPC supports and narrows its return type accordingly. -
[
@solana/kit] #1824b47feb6Thanks @mcintyre94! - Re-export@solana/promisesfrom@solana/kit@solana/kitnow re-exports the@solana/promisespackage, so its helpers —isAbortError,getAbortablePromise, andsafeRace— are available directly from@solana/kitwithout a separate dependency. This is particularly useful alongside@solana/react'suseAction, whose superseded or aborted dispatches reject with anAbortErrorthat callers filter usingisAbortError. -
[
@solana/plugin-interfaces] #1897aa0b625Thanks @lorisleiva! - Add aClientWithFetchAccountsinterfaceThis new plugin interface represents a client that can fetch the encoded content of accounts from their addresses via a
fetchAccounts(addresses, config?)method. Like the other@solana/plugin-interfacescapabilities, it lets plugins provide or require account-fetching without coupling to a concrete RPC. The returned array matches the provided addresses in length and order, usingMaybeEncodedAccountto represent accounts that may not exist. -
[
@solana/react] #1876d6a1adbThanks @mcintyre94! - AddusePayeranduseIdentityReact hooks. Each reads the corresponding value off the client and, when the client advertisessubscribeToPayer/subscribeToIdentity, subscribes so the returned signer always reflects the latest payer/identity. Clients whose value is fixed fall back to a one-time read.If the plugin value throws (for example as the wallet plugin does when it owns payer/identity and a wallet is not connected), this is surfaced as
undefinedin the hooks. -
[
@solana/react] #184194f49bbThanks @mcintyre94! - Make theTClienttype parameter ofuseClientrequired by removing itsobjectdefault, matchinguseClientCapability. Callers should always pass their client's shape (typically an exportedAppClienttype) so installed capabilities are typed at the call site.- const client = useClient(); + const client = useClient<AppClient>();
-
[
@solana/react] #18692193459Thanks @mcintyre94! - AddusePlanTransaction,usePlanTransactions,useSendTransaction, anduseSendTransactionshooks for driving a client's transaction-planning and -sending capabilities as reactive actions. -
[
@solana/react] #1879c27ce2fThanks @mcintyre94! - Add auseAirdrophook that wraps a client'sairdropcapability (ClientWithAirdrop) as a trackeduseAction.dispatch(address, amount)requests an airdrop with an injectedAbortSignal, resolving with the transactionSignature(orundefinedwhen the airdrop is applied without a transaction). -
[
@solana/rpc-api] #1776c8235caThanks @mcintyre94! - Add thegetTransactionsForAddressRPC method type. This method combines address-history discovery and per-transaction fetching into a single query, with server-side filtering, bidirectional sorting, and cursor-based pagination. It will be part of the upcoming solana-rpc spec and is part of thesolana-rpc/superbankproject, and is already available from major RPC providers.It supports both
signaturesandfull(json/jsonParsed/base58/base64) response modes. The shared transaction metadata types also gain an optionalmeta.costUnitsfield, which surfaces ongetTransactionas well. -
[
@solana/rpc-transformers] #191980b3756Thanks @amilz! - Stop upcasting token balanceuiAmountand related numerics tobigintThe response transformer upcasts every JSON integer to a
bigintunless its keypath appears in an allow-list. Because the upcast only applies to integers,uiTokenAmount.uiAmount— anf64on the server — arrived as abigintwhen the balance happened to be a whole number and as anumberwhen it was fractional, so its declared type was correct for some values and wrong for others.uiTokenAmount.uiAmountis now allow-listed ongetTransaction,getBlock, andgetTransactionsForAddresstoken balances.simulateTransactionhad no token balance keypaths allow-listed at all, soaccountIndexanduiTokenAmount.decimalswere upcast there as well. All three are now allow-listed.
@solana/rpc-transformersadditionally exports a newtokenBalancesConfigsarray of token-balance-relative keypaths, alongside the existinginnerInstructionsConfigsandmessageConfig. -
[
@solana/transaction-introspection] #1814c45d5e0Thanks @mcintyre94! -decodeTransactionFromRpcResponsenow accepts confirmed transactions from any RPC method that returns them, not justgetTransaction. It reads only the sharedtransaction/meta/versionenvelope, sogetTransactionsForAddressresults (map over itsdataarray) andgetBlockresults (map over itstransactionsarray, withtransactionDetails: 'full') decode identically, including legacy transactions fetched withoutmaxSupportedTransactionVersion. The'json'overload now types its omittedtransactionasneverrather than an optionalTransaction, reflecting that the JSON path never yields re-encodable wire bytes.
Patch Changes
-
[
@solana/codecs-data-structures] #19118c9eeceThanks @latent-9! - FixgetBitArrayEncoderreturning the wrong next offset. Itswritereturnedsizeinstead ofoffset + size, so a bit array placed before another field in a struct or tuple was overwritten by the following field. It now returnsoffset + size, matching the decoder and the other codecs. -
[
@solana/codecs-data-structures] #1884da10c5aThanks @Swift42! - Avoid copying the remaining buffer ingetArrayDecoder's emptiness checkgetArrayDecoder'sread()tested for an empty byte array withbytes.slice(offset).length === 0, which allocates and copies every byte fromoffsetto the end just to read.lengthoff the result. On large accounts containing many prefixed arrays, maps, or sets this made decoding quadratic in account size. The check is now the equivalent O(1) comparisonoffset >= bytes.length.getMapDecoderandgetSetDecoderdelegate togetArrayDecoderand benefit as well. -
[
@solana/codecs-data-structures] #1809204ed6eThanks @mcintyre94! - Allow boolean predicates passed togetPatternMatchCodecandgetPatternMatchEncoderto narrow to a subtype of the variant's value type. Previously, matching against codecs whose value type is a union — such as the number codecs, whose encode type isnumber | bigint— forced predicates to be typed against the full union (e.g.(value: number | bigint) => …). The predicate parameter is now checked bivariantly, so a narrower predicate like(value: number) => …is accepted, mirroring the ergonomics ofgetPredicateCodecandgetPredicateEncoder. -
[
@solana/kit,@solana/plugin-core] #1883a900eebThanks @mcintyre94! - FixwithCleanupthrowingDisposableStack is not definedon SafariwithCleanupconstructed aDisposableStackunconditionally, but Safari has not shipped explicit resource management — as of Safari 27 it provides neitherDisposableStacknorSymbol.dispose— so any plugin that registers a cleanup function threwReferenceError: Can't find variable: DisposableStackwhile the client was being built.The runtime's own
DisposableStackis still used whenever it exists. Only where it is missing doeswithCleanupfall back to an internal stack that reproduces the behaviour it depends on. ThewithCleanuptest suite now runs twice, once against each stack, so the two cannot drift apart.Note that this fixes disposal on Safari but not
usingdeclarations in your own code, which additionally need aSymbol.disposepolyfill; disposing a client explicitly works either way. -
[
@solana/react] #19079d6be07Thanks @mcintyre94! - Widen the@solana/kitpeer dependency of@solana/reactfrom an exact version to a caret range.@solana/reactpreviously declared"@solana/kit": "workspace:*", which publishes as an exact pin ("@solana/kit": "7.0.0"), so a consumer who advanced@solana/kitwithout advancing@solana/reactin the same step hit an unsatisfiable peer range even though the two are compatible. It now declaresworkspace:^and publishes as^7.1.0. The two packages continue to be released in lockstep at identical versions, so this does not loosen which combinations are actually shipped — it only stops describing a compatible pair as incompatible. -
[
@solana/react] #1825d54b899Thanks @mcintyre94! - Bump the@wallet-standard/uiand@wallet-standard/ui-registrydependencies to^1.0.3and^1.1.1respectively. The1.1.xregistry line is a backward-compatible superset that continues to export the names@solana/reactrelies on, and aligning with it lets consumers that also pull in@solana/kit-plugin-walletresolve a single, shared copy of the wallet-standard UI registry (which is a runtime singleton) instead of splitting across two incompatible copies. -
[
@solana/rpc-api] #191980b3756Thanks @amilz! - Stop upcasting token balanceuiAmountand related numerics tobigintThe response transformer upcasts every JSON integer to a
bigintunless its keypath appears in an allow-list. Because the upcast only applies to integers,uiTokenAmount.uiAmount— anf64on the server — arrived as abigintwhen the balance happened to be a whole number and as anumberwhen it was fractional, so its declared type was correct for some values and wrong for others.uiTokenAmount.uiAmountis now allow-listed ongetTransaction,getBlock, andgetTransactionsForAddresstoken balances.simulateTransactionhad no token balance keypaths allow-listed at all, soaccountIndexanduiTokenAmount.decimalswere upcast there as well. All three are now allow-listed.
@solana/rpc-transformersadditionally exports a newtokenBalancesConfigsarray of token-balance-relative keypaths, alongside the existinginnerInstructionsConfigsandmessageConfig. -
[
@solana/rpc-api] #191782c4cebThanks @amilz! - Stop upcasting transactionversiontobigintThe response transformer upcasts every JSON integer to a
bigintunless its keypath appears in an allow-list.versionwas missing from that allow-list ongetTransaction,getBlocktransactions, andgetTransactionsForAddress, so it arrived at runtime as0nwhile still typechecking asTransactionVersion('legacy' | 0 | 1).A check like
if (transaction.version === 0)therefore compiled cleanly and was always false, with no compiler error and no runtime error. The keypath is now allow-listed andversionarrives as a number, matching its declared type. -
[
@solana/transaction-messages] #1874327760cThanks @mcintyre94! - Update type of compressTransactionMessageUsingAddressLookupTables to reject v1 transactions