facebook

How to Sign Ledger using Solana Wallet Adapter

Calender

17th January 2024

Clock

10 min read

Author
Vishal Prajapati

Associate Consultant - Development

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. 

Author Vishal Prajapati

Vishal is a highly proficient Backend Developer with expertise in Mern Stack technology. He possesses a strong command over designing and developing smart contracts using Solidity and has successfully built REST APIs to facilitate communication between the blockchain and frontend systems. He effectively manages data using MongoDB and MySQL databases. He has a comprehensive skill set that includes JavaScript, Node.js, NestJS, MongoDB, MySQL, Docker, Solidity, and Microservices. Vishal has made significant contributions to various notable projects. Some of his noteworthy works include MisterZ, M2A, TRG Volume Bot, Arbitrage Bot, WethioNFT, Bitorio (Hedgex), Rafa, Apollo, and HODL Token. These projects highlight his ability to tackle diverse challenges and deliver innovative solutions in the field of backend development.

Associate Consultant - Development

bg bg

What's Trending in Tech

bg

Our Offices

India

INDIA

DG-18-009, Tower B,
Emaar Digital Greens, Sector 61,
Gurugram, Haryana
122011.
Unit- 117-120, First Floor,
Welldone Tech Park,
Sector 48, Sohna road,
Gurugram, Haryana
122018.
USA

USA

30N, Gloud St STR E, Sheridan, Wyoming (USA) - 82801
Singapore

SINGAPORE

10 Anson Road, #13-09, International Plaza Singapore 079903.

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.