Since 2009, we have been utilizing our extensive expertise in blockchain technologies to help businesses, both large and small, maximize their efficiency.
Explore More
Since 2009, we have been utilizing our extensive expertise in blockchain technologies to help businesses, both large and small, maximize their efficiency.
Explore More17th January 2024
10 min read
The official Solana wallet adapter (@solana/wallet-adapter) doesn't yet offer native support for Ledger signMessage functionality. So we have to go for alternative solutions. One way is to Build and sign transactions on-client, then send them to a backend for verification and broadcasting. This keeps private keys off the client but involves server-side implementation.
Create a next app and install the following dependencies:
You may also like | Creating a Staking Smart Contract on Solana using Anchor
Create the following files
.env
NEXT_PUBLIC_SOLANA_RPC_HOST=https://api.devnet.solana.com
NEXT_PUBLIC_NETWORK=devnet
src/contexts/ContextProvider.js
import {
ConnectionProvider,
WalletProvider,
} from '@solana/wallet-adapter-react';
import {
PhantomWalletAdapter,
SolflareWalletAdapter,
} from '@solana/wallet-adapter-wallets';
import { useCallback, useMemo } from 'react';
import { AutoConnectProvider, useAutoConnect } from './AutoConnectProvider';
import { NetworkConfigurationProvider } from './NetworkConfigurationProvider';
import dynamic from 'next/dynamic';
import React from 'react';
const ReactUIWalletModalProviderDynamic = dynamic(
async () =>
(await import('@solana/wallet-adapter-react-ui')).WalletModalProvider,
{ ssr: false }
);
const WalletContextProvider = ({ children }) => {
const { autoConnect } = useAutoConnect();
const network = process.env.NEXT_PUBLIC_NETWORK;
const endpoint = process.env.NEXT_PUBLIC_SOLANA_RPC_HOST;
const wallets = useMemo(
() => [new PhantomWalletAdapter(), new SolflareWalletAdapter()],
[network]
);
const onError = useCallback((error) => {
console.error(error);
}, []);
return (
{children}
);
};
export const ContextProvider = ({ children }) => {
return (
<>
{children}
);
};
src/contexts/AutoConnectProvider.js
import React, {
createContext,
useContext,
useMemo,
} from 'react';
import { useLocalStorage } from '@solana/wallet-adapter-react';
export const AutoConnectContext = createContext({});
export function useAutoConnect() {
return useContext(AutoConnectContext);
}
export const AutoConnectProvider = ({ children }) => {
const [autoConnect, setAutoConnect] = useLocalStorage('autoConnect', true);
const ContextValues = useMemo(
() => ({
autoConnect,
setAutoConnect,
}),
[autoConnect, setAutoConnect]
);
return (
{children}
);
};
src/contexts/NetworkConfigurationProvider.js
import { useLocalStorage } from '@solana/wallet-adapter-react';
import { createContext, useContext } from 'react';
export const NetworkConfigurationContext = createContext({});
export function useNetworkConfiguration() {
return useContext(NetworkConfigurationContext);
}
export const NetworkConfigurationProvider = ({ children }) => {
const [networkConfiguration, setNetworkConfiguration] = useLocalStorage(
'network',
process.env.NEXT_PUBLIC_NETWORK
);
return (
{children}
);
};
src/pages/_app.js
import '@/styles/globals.css';
import { ContextProvider } from '@/contexts/ContextProvider';
require('@solana/wallet-adapter-react-ui/styles.css');
export default function App({ Component, pageProps }) {
return (
);
}
src/pages/index.js
import ConnectWalletButton from '@/components/ConnectWalletButton.js';
export default function Home() {
return (
);
}
src/components/ConnectWalletButton.js
import { useConnection, useWallet } from '@solana/wallet-adapter-react';
import {
SystemProgram,
TransactionMessage,
VersionedTransaction,
} from '@solana/web3.js';
import dynamic from 'next/dynamic';
import React, { useCallback, useEffect, useState } from 'react';
const WalletMultiButtonDynamic = dynamic(
async () =>
(await import('@solana/wallet-adapter-react-ui')).WalletMultiButton,
{ ssr: false }
);
const ConnectWalletButton = () => {
const { publicKey, connected, sendTransaction } = useWallet();
const { connection } = useConnection();
const [signature, setSignature] = useState('');
const solanaSign = useCallback(async () => {
const latestBlockhash = await connection.getLatestBlockhash();
const instructions = [
SystemProgram.transfer({
fromPubkey: publicKey,
toPubkey: publicKey,
lamports: 1,
}),
];
const messageLegacy = new TransactionMessage({
payerKey: publicKey,
recentBlockhash: latestBlockhash.blockhash,
instructions,
}).compileToLegacyMessage();
const transaction = new VersionedTransaction(messageLegacy);
try {
const signature = await sendTransaction(transaction, connection);
setSignature(signature);
} catch (error) {}
});
useEffect(() => {
if (!connected) return;
solanaSign();
}, [connected]);
return (
{signature}
);
};
export default ConnectWalletButton;
Also, Explore | What Makes Solana Blockchain Development Stand Out
Start the next app by running the following command:
npm run dev
In your wallet select the account that is connected to the ledger. Then go to http://localhost:3000 and click on Select Wallet. it will connect and sign a transaction from your ledger.
Reference
Source Code - https://github.com/Vishal-oodles/ledger-signing
If you are looking to explore solana blockchain development services for your project, hire our solana developers to get started.