How to Sign Ledger using Solana Wallet Adapter

Posted By : Vishal

Dec 29, 2023

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.

 

Signing Ledger using Solana Wallet Adapter

 

Prerequisites

 

  • Ledger hardware wallet (e.g., Ledger Nano S or X)
  • Solana app installed on your Ledger device (version 1.3.0 or later)
  • Solana wallet adapter integrated into the web application or a dApp you're using
  • Node.js > 18 installed on the device

 

Step 1.

 

Create a next app and install the following dependencies:

 

  • @solana/wallet-adapter-base
  • @solana/wallet-adapter-react
  • @solana/wallet-adapter-react-ui
  • @solana/wallet-adapter-wallets
  • @solana/web3.js

 

You may also like | Creating a Staking Smart Contract on Solana using Anchor

 

Step 2.

 

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


 

 

Step 3.

 

Start the next app by running the following command:

 

npm run dev

 

Step 4.

 

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. 

Leave a

Comment

Name is required

Invalid Name

Comment is required

Recaptcha is required.

blog-detail

April 4, 2024 at 01:32 pm

Your comment is awaiting moderation.

By using this site, you allow our use of cookies. For more information on the cookies we use and how to delete or block them, please read our cookie notice.

Chat with Us
Contact Us

Oodles | Blockchain Development Company

Name is required

Please enter a valid Name

Please enter a valid Phone Number

Please remove URL from text