v1.0.0
What's Changed
WalletAdapter is now chain-generic, so a non-EVM wallet can implement it. This is the major that makes Solana support possible, and it adds the first SVM provider.
Breaking
WalletAdapter is a union discriminated on chainType, with EvmWalletAdapter and SvmWalletAdapter over a shared BaseWalletAdapter. Narrow before reaching for chain-specific methods:
import type { WalletAdapter } from "@opensea/wallet-adapters"
import { createWalletFromEnv, isEvmAdapter, requireEvmAdapter } from "@opensea/wallet-adapters"
const wallet: WalletAdapter = createWalletFromEnv()
if (isEvmAdapter(wallet)) {
await wallet.sendTransaction({
to: "0x0000000000000000000000000000000000000000",
data: "0x",
value: "0",
chainId: 1,
})
}
// Or, for a flow that is EVM-only in substance, throw a message naming the reason.
const evm = requireEvmAdapter(wallet, "swap execution")TransactionRequest is renamed EvmTransactionRequest and kept as a deprecated alias, so the rename alone breaks nobody. The ethers and viem bridges now take EvmWalletAdapter, since both are EVM clients. The five existing providers declare chainType: "evm" and are otherwise unchanged, so an adapter you did not write keeps working.
What actually breaks is an adapter you implement yourself: it now needs a chainType.
Solana
PrivySvmAdapter signs through Privy's wallet RPC. signTransaction is required and sendTransaction is optional, the reverse of EVM, because sign-only providers are ordinary on Solana: a fee payer co-signs, the transaction is simulated first, or the caller broadcasts with its own commitment policy.
import { createWalletFromEnv, isSvmAdapter } from "@opensea/wallet-adapters"
const svm = createWalletFromEnv({ chainType: "svm" })
if (isSvmAdapter(svm)) {
const { signedTransaction } = await svm.signTransaction({ transaction: "AQID" })
}A Privy wallet is bound to one chain_type, so the Solana wallet is a separate wallet with its own id, read from PRIVY_SVM_WALLET_ID. Both chains can be configured at once, and createWalletFromEnv() with no argument still returns the EVM one.
SvmTransactionRequest carries the serialized transaction rather than a to and value, since a Solana transaction is instructions over accounts with no single recipient. That also keeps a Solana SDK out of this package's dependency graph. SvmSignedTransaction.signedTransaction is always base64, whichever form the request used, because that is what Solana RPC sendTransaction takes.
Fixed
PrivyAdapter.signTypedData sent params.typedData as a JSON string containing primaryType, where Privy takes a params.typed_data object containing primary_type. EIP-712 signing through Privy had never worked in any published version. Request bodies are now pinned to the types @privy-io/node publishes, so a field they rename fails a type check here rather than as a 4xx.
Four flows that are EVM-only in substance now say so and reject a Solana wallet with a message naming the reason: x402 settlement, the viem bridge, swaps.execute, and the auth and smoke commands that sign EIP-712.
Not yet verified
No release has signed a real Solana transaction. Every shape here is checked against Privy's published types and the adapter is unit tested against a stubbed transport, but the end-to-end path is unexercised.
Full Changelog: v0.3.5...v1.0.0