Description:
When using a Privy connected Solana wallet (via useWallets()) as a provider for standard Solana Web3 SDKs like @metaplex-foundation/umi or @irys/sdk, transactions fail with a fatal serialization error (TypeError: t is not iterable).
The Root Cause:
The standard @solana/wallet-adapter-react ecosystem (which Metaplex and Irys rely on) expects signTransaction to accept and return fully constructed @solana/web3.js Transaction or VersionedTransaction objects.
However, Privy's v3 ConnectedStandardSolanaWallet strict implementation expects signTransaction to receive a serialized byte array wrapped in an object: { transaction: Uint8Array }. When an SDK passes an object instead of a byte array, the underlying wallet extension (e.g., Backpack) fails to iterate over it during deserialization, resulting in the crash.
Steps to Reproduce:
- Retrieve the active Solana wallet via
const { wallets } = useWallets().
- Map it to the standard adapter shape to use as a signer for Metaplex Umi (
createSignerFromWalletAdapter) or WebIrys.
- Trigger an on-chain action (e.g., minting a Metaplex Core Asset).
- The transaction fails immediately at the serialization layer before reaching the browser extension UI.
Current Workaround:
To bypass the crash, developers are forced to build a custom adapterShim that intercepts the Web3 transaction objects, serializes them to raw bytes for Privy, and then deserializes them back into objects for the SDKs.
// The necessary workaround to bridge Privy to Metaplex Umi / Irys
const activeWallet = solanaWallets[0];
const adapterShim = {
publicKey: new PublicKey(activeWallet.address),
signMessage: async (msg: Uint8Array) => {
const result = await activeWallet.signMessage({ message: msg });
return new Uint8Array(result.signature);
},
signTransaction: async <T extends Transaction | VersionedTransaction>(tx: T): Promise<T> => {
const isVersioned = 'version' in tx;
// 1. Serialize to raw bytes for Privy's Wallet Standard interface
const serialized: Uint8Array = isVersioned
? (tx as VersionedTransaction).serialize()
: (tx as Transaction).serialize({ requireAllSignatures: false });
// 2. Pass bytes to Privy
const { signedTransaction } = await activeWallet.signTransaction({ transaction: serialized });
// 3. Deserialize back to Web3 object for Metaplex/Irys
return (isVersioned
? VersionedTransaction.deserialize(signedTransaction)
: Transaction.from(signedTransaction)) as T;
},
signAllTransactions: async <T extends Transaction | VersionedTransaction>(txs: T[]): Promise<T[]> => {
return Promise.all(txs.map((tx) => adapterShim.signTransaction(tx)));
},
};
Expected Behavior:
Ideally, Privy should export an official "Adapter Shim" hook (e.g., useSolanaAdapter()) that automatically handles this byte array serialization/deserialization under the hood, allowing Privy wallets to drop seamlessly into existing @solana/wallet-adapter-react contexts without crashing downstream SDKs.
Environment:
@privy-io/react-auth: ^3.23.1
@metaplex-foundation/umi: ^1.5.1
@irys/sdk: ^0.2.11
@solana/web3.js: ^1.98.4
Description:
When using a Privy connected Solana wallet (via
useWallets()) as a provider for standard Solana Web3 SDKs like@metaplex-foundation/umior@irys/sdk, transactions fail with a fatal serialization error (TypeError: t is not iterable).The Root Cause:
The standard
@solana/wallet-adapter-reactecosystem (which Metaplex and Irys rely on) expectssignTransactionto accept and return fully constructed@solana/web3.jsTransactionorVersionedTransactionobjects.However, Privy's v3
ConnectedStandardSolanaWalletstrict implementation expectssignTransactionto receive a serialized byte array wrapped in an object:{ transaction: Uint8Array }. When an SDK passes an object instead of a byte array, the underlying wallet extension (e.g., Backpack) fails to iterate over it during deserialization, resulting in the crash.Steps to Reproduce:
const { wallets } = useWallets().createSignerFromWalletAdapter) or WebIrys.Current Workaround:
To bypass the crash, developers are forced to build a custom
adapterShimthat intercepts the Web3 transaction objects, serializes them to raw bytes for Privy, and then deserializes them back into objects for the SDKs.Expected Behavior:
Ideally, Privy should export an official "Adapter Shim" hook (e.g.,
useSolanaAdapter()) that automatically handles this byte array serialization/deserialization under the hood, allowing Privy wallets to drop seamlessly into existing@solana/wallet-adapter-reactcontexts without crashing downstream SDKs.Environment:
@privy-io/react-auth: ^3.23.1@metaplex-foundation/umi: ^1.5.1@irys/sdk: ^0.2.11@solana/web3.js: ^1.98.4