Call a Smart Contract

Call a Smart Contract


In this section, we will guide you through the creation of an application that will call a smart contract to read and write.


Before starting, make sure you have gone through the prerequisites.

Send Ether token to your Ledger Nano ethereum account

To send some ethers on the Ropsten network, go to one of the ropsten faucet websites:

The Ropsten network is not visible on Ledger Live, you can then check the transaction passed on (opens in a new tab).

If the Ropsten and Dimension faucets don't work or the queue is too long, please use another faucet of your choice to receive testnet Ether.

Ropsten Ethereum Network

Go to the Ropsten Ethereum Faucet (opens in a new tab) website put your Wallet Public Key on the input and click on "Send me test Ether"

Ropsten Ethereum Faucet Fig. 1: Ropsten Ethereum Faucet

Dimensions Network

Go to the Dimensions Network (opens in a new tab) website put your Wallet Public Key on the input, do the captcha and click on "Send me test Ether"

Ropsten Ethereum Faucet Fig. 2: Ropsten Ethereum Faucet

Web App Bluetooth (only Nano X)

The Ledger Nano S and S Plus do not have the Bluetooth functionality. This tutorial will only work with a Ledger Nano X.

Please be aware that the Bluetooth implementation is only supported by a few browsers. You can check the browser support (opens in a new tab) for the Web Bluetooth transport.

Project Initialization

The app is build with React, which is a frontend Javascript framework.

First, open a terminal and create a new project. For this tutorial the project will be named "e2e-tutorial-contract". Run:

npx create-react-app e2e-tutorial-contract
cd e2e-tutorial-contract

Open the folder in an editor. The React app initialization creates a "src" folder where you will find all the code.


touch ./src/ConnectLedger.js
touch ./src/SmartContract.js
touch ./src/ethereum.js
touch ./src/polyfill.js

Your folder must look like this.

Folder of the Application Fig. 1: Folder of the Application

To implement the Ledger connexion you will only modify "App.js", "index.js", "ConnectLedger.js”,"SmartContract.js", and ethereum.js”

Code Implementation


In App.js copy-paste the following code:

import React, { useState } from 'react';
import ConnectLedger from './ConnectLedger.js';
import SmartContract from './SmartContract.js';
function App() {
  const [transport, setTransport] = useState(undefined);
  const [eth, setEth] = useState(undefined);
  const [address, setAddress] = useState(undefined);
  const saveInfo = (info) => {
  return (
    <div className='container'>
      !transport ?
      <ConnectLedger onTransport={(info) => saveInfo(info)}></ConnectLedger> :
      <SmartContract address={address} eth={eth}></SmartContract>
export default App;


In App.js copy-paste the following code:

global.Buffer = require("buffer").Buffer;


in the index.js add these line

import './polyfill'
import 'bootstrap/dist/css/bootstrap.min.css';


In ConnectLedger.js, copy-paste the following code:

import React from 'react';
import TransportWebBLE from "@ledgerhq/hw-transport-web-ble";
import Eth from "@ledgerhq/hw-app-eth";
function ConnectLedger({onTransport}) {
  const connectLedger = async() => {
    const transport = await TransportWebBLE.create();
    const eth = new Eth(transport);
    const {address} = await eth.getAddress("44'/60'/0'/0/0", false);
  return (
    <div className='container'>
      <div className='row'>
        <div className='col-sm-4 mt-5 mx-auto'>
          <button onClick={connectLedger}>Connect Your Ledger</button>
export default ConnectLedger;


In "SmartContract.js", copy-paste the following code:

import React, { useState } from 'react';
import getBlockchain from './ethereum.js';
import { ethers } from 'ethers';
function SmartContract({eth,address}) {
  const [simpleStorage, setSimpleStorage] = useState(undefined);
  const [data, setData] = useState(undefined);
  const [provider, setProvider] = useState(undefined);
  const [url, setUrl] = useState(undefined);
  const smartContractRead = async() => {
    const provider = new ethers.providers.JsonRpcProvider('');
    const { simpleStorage } = await getBlockchain(provider);
    const data = await simpleStorage.readData();
  const updateData = async e => {
    const dataInput =[0].value;
    const { data } = await simpleStorage.populateTransaction['updateData(uint256)'](dataInput);
    const unsignedTx = {
      to: simpleStorage.address,
      gasPrice: (await provider.getGasPrice())._hex,
      gasLimit: ethers.utils.hexlify(100000),
      nonce: await provider.getTransactionCount(address, "latest"),
      chainId: 3,
      data: data,
    const serializedTx = ethers.utils.serializeTransaction(unsignedTx).slice(2);
    const signature = await eth.signTransaction(
    //Parse the signature
    signature.r = "0x"+signature.r;
    signature.s = "0x"+signature.s;
    signature.v = parseInt("0x"+signature.v);
    signature.from = address;
    //Serialize the same transaction as before, but adding the signature on it
    const signedTx = ethers.utils.serializeTransaction(unsignedTx, signature);
    const hash = (await provider.sendTransaction(signedTx)).hash;
    setUrl("" + hash);
  return (
    <div className='container'>
      <div className='row'>
        <div className='col-sm-4'>
          <p>{data ? data.toString() : "..." }</p>
          <button onClick={() => smartContractRead()}>Get Data</button>
        <div className='col-sm-4'>
          <h2>Change data</h2>
          <form className="form-inline" onSubmit={e => updateData(e)}>
              className="btn btn-primary"
        <div className="mt-5 mx-auto d-flex flex-column">
            Ropsten Etherscan :
          <p><a href={url} target="_blank" rel="noreferrer">{url}</a></p>
export default SmartContract;


In "ethereum.js", copy-paste the following code:

import { Contract } from 'ethers';
const getBlockchain = (provider) =>
  new Promise( async (resolve, reject) => {
    if(provider) {
      const simpleStorage = new Contract(
            "inputs": [],
            "name": "data",
            "outputs": [
                "internalType": "uint256",
                "name": "",
                "type": "uint256"
            "stateMutability": "view",
            "type": "function"
            "inputs": [],
            "name": "readData",
            "outputs": [
                "internalType": "uint256",
                "name": "",
                "type": "uint256"
            "stateMutability": "view",
            "type": "function"
            "inputs": [
                "internalType": "uint256",
                "name": "_data",
                "type": "uint256"
            "name": "updateData",
            "outputs": [],
            "stateMutability": "nonpayable",
            "type": "function"
    reject('Provider not recognized');
export default getBlockchain;

Dependencies Installation


npm install --save bootstrap
npm install --save ethers
npm install --save @ledgerhq/hw-app-eth
npm install --save @ledgerhq/hw-transport-web-ble
npm install --save buffer
PackageWhat does it do?
bootstrap (opens in a new tab)It allows you to use the Bootstrap CSS framework.
ethers (opens in a new tab)It provides you with all the methods to interact with the Ethereum blockchain.
@ledgerhq/hw-app-eth (opens in a new tab)It will help you ask your Nano to access the ethereum address.
@ledgerhq/hw-transport-web-ble (opens in a new tab)It provides you with all the methods to interact with your Ledger Nano X with a Bluetooth connexion.
buffer (opens in a new tab)The goal is to provide an API that is 100% identical to node's Buffer API.

Package.json Dependencies

Now that the dependencies are installed you can find them in the "package.js". This is how your "package.json" shoud look like:

  "name": "e2e-tutorial",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@ledgerhq/hw-app-eth": "^6.26.0",
    "@ledgerhq/hw-transport-web-ble": "^6.24.0",
    "@testing-library/jest-dom": "^5.16.2",
    "@testing-library/react": "^12.1.3",
    "@testing-library/user-event": "^13.5.0",
    "bootstrap": "^5.1.3",
    "buffer": "^6.0.3",
    "ethers": "^5.5.4",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "5.0.0",
    "web-vitals": "^2.1.4"
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  "eslintConfig": {
    "extends": [
  "browserslist": {
    "production": [
      "not dead",
      "not op_mini all"
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"

Web App Test

Start the Development Server


npm run start

All the browser do not support the Bluetooth please look at the browser support .

Now the application is up and running. Open the browser and go to localhost:3000, it will display :

Application Running on Browser Fig. 2: Application Running on Browser

Don't click on the button yet.

Launch Ethereum App

Before clicking on the button, unlock your Nano X and run the Ethereum application. The steps are described below.

Nano Enter Code Pin
Fig. 3: Ledger Enter Code Pin

Embedded Application
Fig. 4: Ledger Application

Nano Run Application
Fig. 5: Application is running

Connect Your Nano to the Application

Now you can click on the button and a popup open. Choose your Ledger Nano X and click connexion

Connect the Ledger with Bluetooth Fig. 6: Connect the Ledger with Bluetooth

Read the data of a Smart Contract

Now you can click on the button "Get Data" to read the data of the smart contract. Then the data will be displayed on the screen.

Get data from a smart contract Fig. 7: Get data from a smart contract

Update the data of a Smart Contract

Now instead of reading data, we will overwrite the data by calling a function of the smart contract which is "UpdateData".

Change data from a smart contract Fig. 8: Change data from a smart contract

Verify the Address on your Nano

For security reasons, the address will also be displayed on your Ledger Nano X to verify and confirm the address.

Nano Review Screen
Nano Amount Screen
Fig. 9: Nano Review Screen
Fig. 10: Nano Amount Screen

Nano Address Screen
Nano Network Screen
Fig. 11: Nano Address Screen
Fig. 12: Nano Network Screen

Nano Max Fees Screen
Nano Accept and Send Screen
Fig. 13: Nano Max Fees Screen
Fig. 14: Nano Accept and Send Screen

For the Smart Contract call you need to allow blind signing because the smart contract that is called in the tutorial is not yet verified and reviewed by Ledger. But if the smart contract you are calling is accepted by Ledger do not enable blind signing. Moreover, we do not recommend enabling blind signing in other situations as the main purpose to sign with Ledger is the 'Sign what you see' system. And by enabling blind signing it can not ensure that what you see is what you get.

Review the Transaction on Ropsten Etherscan

By updating the data a transaction is created to change this data, it can be verified on Ropsten Etherscan.

Ropsten Etherscan
Fig. 15: Ropsten Etherscan

Wait till the status passes to Success.

Ropsten Etherscan
Fig. 16: Ropsten Etherscan

Verify the update of data

Finally, to verify if data was updated, open the web application and click on "Get data".

Verify the data
Fig. 17: Verify the data

Verify the data
Fig. 18: Verify the data

Congratulations, you have successfully built your first application connected with Ledger!

Copyright © Ledger SAS. All rights reserved. Ledger, Ledger Nano S, Ledger Vault, Bolos are registered trademarks of Ledger SAS