Skip to content

v1.0.0

Choose a tag to compare

@ryanio ryanio released this 09 Sep 00:21
· 4 commits to main since this release

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