- How can I get support?
- Can I use this with ___?
- What does this error mean?
- How can I sign and verify messages?
Please ask questions in the #developer-support channel on the Solana Discord: https://discord.com/invite/solana
After reading this FAQ, if you've found a bug or you'd like to request a feature, please open an issue.
Yes, see the react-ui-starter package.
Yes, use the useAnchorWallet()
hook in the React package to easily get an Anchor-compatible Wallet interface.
Yes, see the nextjs-starter package for very basic configuration, or the example package for more complete configuration.
If you're using one of the react-ui, material-ui, or ant-design packages too, make sure to configure the WalletModalProvider
or WalletDialogProvider
context as shown here.
Yes, see the material-ui-starter package.
Yes, see the ant-design package.
Yes, see the vue package.
Yes, see the angular package.
Yes, but you may need to set up polyfills for certain imported modules.
For example, you may need to install buffer
:
yarn add buffer
And configure webpack.config.js
:
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer']
})
],
resolve: {
fallback: {
crypto: false
}
}
};
Yes, but you may need to provide custom build configuration.
Most of the packages are built using the TypeScript compiler, which outputs modular ES6 with import
/export
statements.
If you're using Create React App, craco, or one of the React-based starter projects using them, this should be handled automatically.
If you're using Next.js, this requires configuration, which is provided in the nextjs-starter package.
If you're using something else, you may have to configure your build tool to transpile the packages similarly to how it's done in the Next.js config. Please open an issue or pull request to document your solution!
This can happen if you're cloning the project and building it from the source and you missed a step.
If this doesn't fix the problem, please open an issue.
[...] is not a function
/ [...] is undefined
/ Uncaught TypeError: Cannot destructure property
/ Uncaught (in promise) WalletNotConnectedError
This can happen if you don't wrap your dApp with the WalletContext
and ConnectionContext
provided by the react package.
See issues #62, #73, and #85.
This shouldn't happen if you're using one of the starter projects, since they set up the contexts for you.
This can happen if you try to use signTransaction
, signAllTransactions
, or signMessage
without checking if they are defined first.
sendTransaction
is the primary method that all wallets support, and it signs transactions.
The other methods are optional APIs, so you have to feature-detect them before using them.
Please see issue #72.
This can happen if you're using one of the starter projects and you didn't configure Torus for your dApp.
Go to https://developer.tor.us to sign up for your own unique client ID. Then use this ID in your configuration:
const wallets = useMemo(() => [
// ...
getTorusWallet({
options: { clientId: '<YOUR CLIENT ID>' },
}),
// ...
], [network]);
Some wallet adapters like Phantom and Sollet provide a signMessage
method for signing arbitrary bytes.
The signature string returned by this method can be verified using tweetnacl-js using the public key from the adapter.
This can be used to sign offline -- without sending a transaction -- and prove a user controls a given private key.
import { useWallet } from '@solana/wallet-adapter-react';
import bs58 from 'bs58';
import React, { FC, useCallback } from 'react';
import { sign } from 'tweetnacl';
export const SignMessageButton: FC = () => {
const { publicKey, signMessage } = useWallet();
const onClick = useCallback(async () => {
try {
// `publicKey` will be null if the wallet isn't connected
if (!publicKey) throw new Error('Wallet not connected!');
// `signMessage` will be undefined if the wallet doesn't support it
if (!signMessage) throw new Error('Wallet does not support message signing!');
// Encode anything as bytes
const message = new TextEncoder().encode('Hello, world!');
// Sign the bytes using the wallet
const signature = await signMessage(message);
// Verify that the bytes were signed using the private key that matches the known public key
if (!sign.detached.verify(message, signature, publicKey.toBytes())) throw new Error('Invalid signature!');
alert(`Message signature: ${bs58.encode(signature)}`);
} catch (error: any) {
alert(`Signing failed: ${error?.message}`);
}
}, [publicKey, signMessage]);
return signMessage ? (<button onClick={onClick} disabled={!publicKey}>Sign Message</button>) : null;
};