Posted By : Vishal
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.
November 21, 2024 at 12:28 pm
Your comment is awaiting moderation.