<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aniket Ambore</title>
    <description>The latest articles on DEV Community by Aniket Ambore (@anipy).</description>
    <link>https://dev.to/anipy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1185618%2F83f25031-1916-4644-881d-3684c1f29ac1.png</url>
      <title>DEV Community: Aniket Ambore</title>
      <link>https://dev.to/anipy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anipy"/>
    <language>en</language>
    <item>
      <title>Tutorial: How to Develop a Nostr Wallet Connect Mobile App Using Flutter and NWC</title>
      <dc:creator>Aniket Ambore</dc:creator>
      <pubDate>Sun, 23 Jun 2024 11:30:22 +0000</pubDate>
      <link>https://dev.to/anipy/tutorial-how-to-develop-a-nostr-wallet-connect-mobile-app-using-flutter-and-nwc-3kcb</link>
      <guid>https://dev.to/anipy/tutorial-how-to-develop-a-nostr-wallet-connect-mobile-app-using-flutter-and-nwc-3kcb</guid>
      <description>&lt;p&gt;Hello everyone! My name is Aniket (aka &lt;a href="https://x.com/Anipy1" rel="noopener noreferrer"&gt;Anipy&lt;/a&gt;) and in this tutorial, I'm going to show you how to develop a Nostr Wallet Connect mobile app using Flutter and the &lt;a href="https://pub.dev/packages/nwc" rel="noopener noreferrer"&gt;NWC Dart package&lt;/a&gt;. Before we dive into the tutorial, it's important to familiarize yourself with the &lt;a href="https://github.com/nostr-protocol/nips/blob/master/47.md" rel="noopener noreferrer"&gt;NIP47&lt;/a&gt; protocol to better understand Nostr Wallet Connect.&lt;/p&gt;

&lt;p&gt;In brief, Nostr Wallet Connect (NWC) is a protocol that allows applications to access a remote Lightning wallet. Imagine you’ve developed a simple multiplayer game like tic-tac-toe. Your game works great, but you want to add real-world rewards using satoshis (sats). One way to achieve this is by using Nostr Wallet Connect.&lt;/p&gt;

&lt;p&gt;With NWC, users can connect their remote Lightning wallets to your app. Now, your tic-tac-toe game can interact with these wallets. Once the connection is established, your game can request payments from the user’s Lightning wallet.&lt;/p&gt;

&lt;p&gt;Here’s a practical example: before starting a game, both players agree that the loser will pay an LN invoice to the winner. At the end of the game, your app will automatically create an LN invoice for the winner’s connected wallet and pay it from the loser’s connected wallet. This rewarding mechanism is made possible by NWC.&lt;/p&gt;

&lt;p&gt;NWC allows users to connect their remote Lightning wallets to your app easily, ensuring their wallets are available when needed. If a user ever wants to disable this connection, they can simply disconnect it.&lt;/p&gt;

&lt;p&gt;Let's get started on building this exciting functionality into your Flutter app!&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Before we dive into coding, let's start by grabbing the "&lt;strong&gt;starter&lt;/strong&gt;" project for this tutorial. Open your terminal and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;-b&lt;/span&gt; starter &lt;span class="nt"&gt;--single-branch&lt;/span&gt; https://github.com/aniketambore/nostr_pay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will clone the &lt;strong&gt;starter&lt;/strong&gt; project, saving you time and allowing you to focus on the exciting parts of this tutorial.&lt;/p&gt;

&lt;p&gt;Feeling the excitement? Great! Now, fire up your favorite code editor, whether it’s VS Code or Android Studio.&lt;/p&gt;

&lt;p&gt;You may see some errors in the &lt;strong&gt;starter&lt;/strong&gt; project initially. To fix this, head over to the &lt;code&gt;pubspec.yaml&lt;/code&gt; file and locate the &lt;code&gt;# TODO: Add NWC package here&lt;/code&gt; comment. Replace it with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nwc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, run &lt;code&gt;flutter pub get&lt;/code&gt; to set things up, and then launch the app. At this stage, it’s a straightforward UI project, but we’ll soon infuse it with some Nostr Wallet Connect magic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FHDyKXjy%2Fss1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FHDyKXjy%2Fss1.png" alt="Nostr Pay - Initial Screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Files
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;starter&lt;/strong&gt; project includes several files to help you out. Let’s take a brief tour of these files to understand their purpose before we dive into developing the Nostr Wallet Connect functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assets folder
&lt;/h3&gt;

&lt;p&gt;Inside the &lt;strong&gt;assets&lt;/strong&gt; directory, you'll find icons, images, and lottie files that will be used to build this app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FDGmpB5n%2Fassets.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FDGmpB5n%2Fassets.png" alt="Nostr Pay - Project assets folder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Folder structure
&lt;/h3&gt;

&lt;p&gt;In the &lt;strong&gt;lib&lt;/strong&gt; directory, you'll notice various folders, each serving a specific purpose:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F6vQHkSR%2Flib.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F6vQHkSR%2Flib.png" alt="Nostr Pay - Project lib folder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  State Management (BLoC)
&lt;/h4&gt;

&lt;p&gt;In &lt;code&gt;lib/bloc&lt;/code&gt;, you'll find files for state and credentials management. We’ll discuss these further in the article.&lt;/p&gt;

&lt;h4&gt;
  
  
  Component Library Folder
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;lib/component_library&lt;/code&gt; contains all the reusable UI components that might be used across different screens.&lt;/p&gt;

&lt;h4&gt;
  
  
  Handlers
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;lib/handlers&lt;/code&gt; directory currently contains the &lt;code&gt;PaymentResultHandler&lt;/code&gt;, which listens to a stream and performs navigation actions based on the received payment results.&lt;/p&gt;

&lt;h4&gt;
  
  
  Models
&lt;/h4&gt;

&lt;p&gt;In &lt;code&gt;lib/models&lt;/code&gt;, you’ll find the model objects used in our app, defining how data is structured and managed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Routes
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;lib/routes&lt;/code&gt; directory contains all the screens and dialogs displayed in the app.&lt;/p&gt;

&lt;h4&gt;
  
  
  Services
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;lib/services&lt;/code&gt; directory includes services like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Device&lt;/code&gt;: Provides methods to copy text to the clipboard and share text using the device's functionality.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Keychain&lt;/code&gt;: Provides methods to securely store, retrieve, and delete key-value pairs in secure storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  App Libraries
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;starter&lt;/strong&gt; project comes with a set of useful libraries listed in &lt;code&gt;pubspec.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nwc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.0.1&lt;/span&gt;
  &lt;span class="na"&gt;flutter_bloc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^8.1.5&lt;/span&gt;
  &lt;span class="na"&gt;flutter_secure_storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^4.2.1&lt;/span&gt;
  &lt;span class="na"&gt;flutter_svg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.0.10+1&lt;/span&gt;
  &lt;span class="na"&gt;hydrated_bloc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^9.1.5&lt;/span&gt;
  &lt;span class="na"&gt;connectivity_plus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^6.0.3&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.9.0&lt;/span&gt;
  &lt;span class="na"&gt;path_provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.1.3&lt;/span&gt;
  &lt;span class="na"&gt;rxdart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.27.7&lt;/span&gt;
  &lt;span class="na"&gt;flutter_fgbg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.3.0&lt;/span&gt;
  &lt;span class="na"&gt;intl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.19.0&lt;/span&gt;
  &lt;span class="na"&gt;qr_flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^4.1.0&lt;/span&gt;
  &lt;span class="na"&gt;share_plus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^9.0.0&lt;/span&gt;
  &lt;span class="na"&gt;toastification&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.0.0&lt;/span&gt;
  &lt;span class="na"&gt;bolt11_decoder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.0.2&lt;/span&gt;
  &lt;span class="na"&gt;auto_size_text&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^3.0.0&lt;/span&gt;
  &lt;span class="na"&gt;lottie&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^3.1.2&lt;/span&gt;
  &lt;span class="na"&gt;flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sdk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what they help you to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nwc&lt;/code&gt;: Simplifies the integration of Nostr Wallet Connect by providing methods for handling NWC-related functionalities.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;flutter_bloc&lt;/code&gt;: Implements the BLoC (Business Logic Component) design pattern for state management, separating presentation and business logic.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;flutter_secure_storage&lt;/code&gt;: Securely stores key-value pairs, useful for sensitive data.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;flutter_svg&lt;/code&gt;: Renders SVG images.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hydrated_bloc&lt;/code&gt;: Enhances &lt;code&gt;flutter_bloc&lt;/code&gt; by persisting state to disk and restoring it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;connectivity_plus&lt;/code&gt;: Checks network connectivity status.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;path&lt;/code&gt;: Provides utilities for working with file and directory paths.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;path_provider&lt;/code&gt;: Helps access the file system path on the device.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rxdart&lt;/code&gt;: Extends Dart's Streams with reactive programming.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;flutter_fgbg&lt;/code&gt;: Detects when the app moves between the foreground and background.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;intl&lt;/code&gt;: Supports internationalization and localization.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;qr_flutter&lt;/code&gt;: Generates QR codes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;share_plus&lt;/code&gt;: Provides functionality for sharing content.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;toastification&lt;/code&gt;: Shows customizable toast notifications.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bolt11_decoder&lt;/code&gt;: Decodes Bolt11 payment invoices used in the Lightning Network.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;auto_size_text&lt;/code&gt;: Automatically resizes text to fit within its bounds.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lottie&lt;/code&gt;: Renders lottie animations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  NWC Initialization
&lt;/h2&gt;

&lt;p&gt;Let's start with initializing the &lt;code&gt;NWC&lt;/code&gt; class. Open the &lt;code&gt;main.dart&lt;/code&gt; file and locate &lt;code&gt;// TODO: Import nwc package&lt;/code&gt;. Replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:nwc/nwc.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, find &lt;code&gt;// TODO: Initialize Nostr Wallet Connect class&lt;/code&gt; and replace it along with the nwc variable with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;nwc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NWC&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, open the &lt;code&gt;lib/bloc/nwc_account/nwc_account_cubit.dart&lt;/code&gt; file, import the NWC package, and locate &lt;code&gt;// TODO: Instance of the Nostr Wallet Connect class&lt;/code&gt;. Replace it and the &lt;code&gt;_nwc&lt;/code&gt; variable with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;NWC&lt;/span&gt; &lt;span class="n"&gt;_nwc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, locate &lt;code&gt;// TODO: Change balance controller and stream type to Get_Balance_Result&lt;/code&gt; and replace it and the &lt;code&gt;_walletBalanceController&lt;/code&gt; and &lt;code&gt;walletBalanceStream&lt;/code&gt; variables with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Get_Balance_Result&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_walletBalanceController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Get_Balance_Result&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Get_Balance_Result&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;walletBalanceStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_walletBalanceController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Monitoring Changes
&lt;/h2&gt;

&lt;p&gt;We initialized the wallet balance controller and stream types in the previous step. Now, let's use the &lt;code&gt;walletBalanceStream&lt;/code&gt; to monitor changes in the wallet balance by working on the &lt;code&gt;_watchAccountChanges()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Update the types to match the actual data type&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Rx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;combineLatest&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Get_Balance_Result&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NWCAccountState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;([&lt;/span&gt;&lt;span class="n"&gt;walletBalanceStream&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Rx.combineLatest&lt;/code&gt;: Emits the latest values from the &lt;code&gt;walletBalanceStream&lt;/code&gt; whenever it emits a new value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Check if wallet balance result is not null&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;first&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// TODO: Assemble and return a new NWCAccountState based on the latest balance result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;values&lt;/code&gt;: Holds the latest values from the combined streams, where &lt;code&gt;values.first&lt;/code&gt; corresponds to the latest value from &lt;code&gt;walletBalanceStream&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We're checking if the first value (representing the latest balance result) is not null.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, update the state by locating &lt;code&gt;// TODO: Assemble and return a new NWCAccountState based on the latest balance result&lt;/code&gt; and replacing it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;assembleNWCAccountState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="o"&gt;!.&lt;/span&gt;&lt;span class="na"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;first&lt;/span&gt;&lt;span class="o"&gt;!.&lt;/span&gt;&lt;span class="na"&gt;maxAmount&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;assembleNWCAccountState&lt;/code&gt;: A helper function (located in &lt;code&gt;lib/bloc/nwc_account/nwc_account_state.dart&lt;/code&gt;) that constructs a new &lt;code&gt;NWCAccountState&lt;/code&gt; object using the provided &lt;code&gt;balance&lt;/code&gt;, &lt;code&gt;maxAmount&lt;/code&gt;, and the current state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this, we have completed the &lt;code&gt;_watchAccountChanges&lt;/code&gt; method, which combines the latest values from the &lt;code&gt;walletBalanceStream&lt;/code&gt; to monitor changes in the wallet balance. When the balance changes, it constructs a new state using &lt;code&gt;assembleNWCAccountState&lt;/code&gt; and emits this new state. If the balance is null or no change occurs, it returns the current state, ensuring the app’s state is always up-to-date with the latest balance information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inside the Constructor
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;NWCAccountCubit&lt;/code&gt; constructor initializes the state, sets up listeners, and performs initial actions. Let's work on that in this section.&lt;/p&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Listen to account changes and emit updated state&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="n"&gt;_watchAccountChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'State changed: &lt;/span&gt;&lt;span class="si"&gt;$acc&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;_watchAccountChanges().listen((acc) {...})&lt;/code&gt;: Sets up a listener for the stream returned by &lt;code&gt;_watchAccountChanges()&lt;/code&gt;. Whenever a new state (&lt;code&gt;acc&lt;/code&gt;) is emitted by the stream, the callback is executed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;emit(acc);&lt;/code&gt;: Emits the new state, updating the state of the Cubit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Disable unnecessary logs from the logger utils&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;_nwc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loggerUtils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disableLogs&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we’re disabling logging from the NWC utility to reduce log noise in the production environment, although you can keep it if desired.&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Connect if the current state type is not none&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;NWCConnectTypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we check if a NWC wallet is already initialized. If it is, we connect to it; otherwise, we do not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect
&lt;/h2&gt;

&lt;p&gt;Until now, we haven't talked much about NWC, focusing instead on streams and listeners. Let's now discuss the &lt;code&gt;connect&lt;/code&gt; method. First, look at the parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Future&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;connectionURI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;restored&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;NWCConnectTypes&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;connectionURI&lt;/code&gt;: A string representing the URI used to establish the connection between the remote lightning wallet and our app.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;restored&lt;/code&gt;: A boolean flag indicating whether the connection is being restored.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt;: An optional parameter of type &lt;code&gt;NWCConnectTypes&lt;/code&gt; (an enum) specifying the type of connection. It has three values: &lt;code&gt;none&lt;/code&gt;, &lt;code&gt;nwc&lt;/code&gt;, and &lt;code&gt;alby&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;none&lt;/code&gt;: No wallet is connected to the app.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nwc&lt;/code&gt;: A wallet is connected, where the user manually copies and pastes the connection URI from the remote lightning wallet into the app.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;alby&lt;/code&gt;: The Alby wallet is connected. (This article does not cover the Alby wallet connection.)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Now, locate &lt;code&gt;// TODO: Parse the Nostr Connect URI&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;parsedUri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_nwc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nip47&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseNostrConnectUri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionURI&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This uses the &lt;code&gt;parseNostrConnectUri(connectionURI)&lt;/code&gt; method to parse the connection URI entered by the user, extracting components such as &lt;code&gt;secret&lt;/code&gt;, &lt;code&gt;pubkey&lt;/code&gt;, &lt;code&gt;relay&lt;/code&gt;, and &lt;code&gt;lud16&lt;/code&gt;. We will discuss &lt;code&gt;connectionURI&lt;/code&gt; more in the following sections.&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Derive the public key from the parsed URI secret&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;myPubkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_nwc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;keysService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;derivePublicKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;privateKey:&lt;/span&gt; &lt;span class="n"&gt;parsedUri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we use the &lt;code&gt;derivePublicKey(privateKey: parsedUri.secret)&lt;/code&gt; method to derive the public key (&lt;code&gt;myPubkey&lt;/code&gt;) from the parsed secret (&lt;code&gt;parsedUri.secret&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Store the secret using the credentials manager&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_credentialsManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;storeSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;secret:&lt;/span&gt; &lt;span class="n"&gt;parsedUri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This uses the &lt;code&gt;_credentialsManager.storeSecret(secret: parsedUri.secret)&lt;/code&gt; method to securely store the parsed secret (private key) using the credentials manager (&lt;code&gt;_credentialsManager&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Emit the new state with the updated properties&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;copyWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;type:&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;walletPubkey:&lt;/span&gt; &lt;span class="n"&gt;parsedUri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pubkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;myPubkey:&lt;/span&gt; &lt;span class="n"&gt;myPubkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;relay:&lt;/span&gt; &lt;span class="n"&gt;parsedUri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;relay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;lud16:&lt;/span&gt; &lt;span class="n"&gt;parsedUri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lud16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This emits a new state using &lt;code&gt;emit(state.copyWith(...))&lt;/code&gt;, updating the type, &lt;code&gt;walletPubkey&lt;/code&gt;, &lt;code&gt;myPubkey&lt;/code&gt;, &lt;code&gt;relay&lt;/code&gt;, and &lt;code&gt;lud16&lt;/code&gt; based on the parsed URI components.&lt;/p&gt;

&lt;p&gt;So the &lt;code&gt;connect&lt;/code&gt; method parses the URI to extract necessary parameters, derives the public key from the secret, securely stores the secret, updates the state with connection details, and initialize the connection to enable ongoing communication and synchronization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initializing Relay and Handling Events
&lt;/h2&gt;

&lt;p&gt;Let's move on to the &lt;code&gt;_initializeConnection()&lt;/code&gt; method. First, locate &lt;code&gt;// TODO: Initialize the relays service with the relay URL&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_nwc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;relaysService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;relaysUrl:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;relay&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This initializes the &lt;code&gt;relaysService&lt;/code&gt; provided by &lt;code&gt;_nwc&lt;/code&gt; with the relay URL obtained from the current state, preparing the NWC to communicate with the specified relay.&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Create a subscription filter for events&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;subToFilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;filters:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;kinds:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;23195&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="nl"&gt;authors:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;walletPubkey&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="nl"&gt;since:&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a request object with a filter specifying the types of events (&lt;code&gt;kinds&lt;/code&gt;) and authors (&lt;code&gt;authors&lt;/code&gt;) to subscribe to. It filters events of kind &lt;strong&gt;23195&lt;/strong&gt;, the response event kind in the protocol, authored by the current wallet public key (&lt;code&gt;state.walletPubkey&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Start the events subscription using the relays service&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;nostrStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_nwc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;relaysService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startEventsSubscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;request:&lt;/span&gt; &lt;span class="n"&gt;subToFilter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;onEose:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eose&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'subscriptionId: &lt;/span&gt;&lt;span class="si"&gt;${eose.subscriptionId}&lt;/span&gt;&lt;span class="s"&gt;, relay: &lt;/span&gt;&lt;span class="si"&gt;$relay&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This initiates a subscription (&lt;code&gt;startEventsSubscription&lt;/code&gt;) to the Nostr relay service (&lt;code&gt;_nwc.relaysService&lt;/code&gt;) based on the defined filter request. It listens for specific events matching the filter criteria (&lt;code&gt;Filter&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Restore the secret from the credentials manager&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_credentialsManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;restoreSecret&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This restores the secret (private key) associated with the wallet from the credentials manager. This secret is necessary for decrypting incoming event content.&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Listen to the nostr stream for events&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;nostrStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// TODO: Event handling logic&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sets up a listener on the &lt;code&gt;nostrStream.stream&lt;/code&gt; to listen for incoming events (&lt;code&gt;Event&lt;/code&gt; objects) from the Nostr relay service. It executes the provided callback whenever a new event is received.&lt;/p&gt;

&lt;p&gt;Next, replace &lt;code&gt;// TODO: Event handling logic&lt;/code&gt; with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;23195&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;decryptedContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_nwc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nip04&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;walletPubkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 3&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_nwc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nip47&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseResponseResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decryptedContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 4&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get_balance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Handle get_balance result&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;make_invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Handle make_invoice result&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pay_invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Handle pay_invoice result&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookup_invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Handle lookup_invoice result&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Handle error result&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We first check if the event that we received has the &lt;code&gt;kind&lt;/code&gt; equal to &lt;strong&gt;23195&lt;/strong&gt; (&lt;a href="https://github.com/nostr-protocol/nips/blob/master/47.md#events" rel="noopener noreferrer"&gt;the response event kind&lt;/a&gt;) and ensure the content is not null.&lt;/li&gt;
&lt;li&gt;As defined in &lt;strong&gt;Nip47&lt;/strong&gt;, the content of requests and responses is encrypted with &lt;strong&gt;NIP04&lt;/strong&gt;. Therefore, we decrypt the content of the incoming event with the retrieved secret and the wallet public key.&lt;/li&gt;
&lt;li&gt;We parse the decrypted content to determine the type of result (&lt;code&gt;NWCResultType&lt;/code&gt;) contained in the event.&lt;/li&gt;
&lt;li&gt;Finally, we handle different types of results (&lt;code&gt;get_balance&lt;/code&gt;, &lt;code&gt;make_invoice&lt;/code&gt;, &lt;code&gt;pay_invoice&lt;/code&gt;, &lt;code&gt;lookup_invoice&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt;) and update the state accordingly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Up to this point, we have set up subscriptions to receive specific events, decrypt incoming event content, handle different types of results (such as balance updates, invoice creation or payment, lookup results, and errors), and update the app state accordingly. We will cover event handling in the following section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing Events to Relays
&lt;/h2&gt;

&lt;p&gt;We'll now work on the &lt;code&gt;_sentToRelay&lt;/code&gt; method, which is responsible for encrypting a given message, creating an event, and sending it to the Nostr relay. Let's break down each part of this method.&lt;/p&gt;

&lt;p&gt;First, locate &lt;code&gt;// TODO: Restore the secret from the credentials manager&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_credentialsManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;restoreSecret&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've covered this in previous sections, so you already understand its purpose.&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Encrypt the message using NIP04&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_nwc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nip04&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;walletPubkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;jsonEncode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This encrypts the &lt;code&gt;message&lt;/code&gt; content using the &lt;strong&gt;NIP04&lt;/strong&gt; encryption method provided. It uses the retrieved secret (private key) and the wallet public key to encrypt the JSON-encoded message.&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Create an event request with the encrypted content&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromPartialData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;kind:&lt;/span&gt; &lt;span class="mi"&gt;23194&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;content:&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;tags:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'p'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;walletPubkey&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nl"&gt;createdAt:&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="nl"&gt;keyPairs:&lt;/span&gt; &lt;span class="n"&gt;KeyPairs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;private:&lt;/span&gt; &lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This constructs an Event object (request) using the encrypted content. It assigns a kind (&lt;strong&gt;23194&lt;/strong&gt; for a request, &lt;a href="https://github.com/nostr-protocol/nips/blob/master/47.md#events" rel="noopener noreferrer"&gt;as defined in the NIP47 protocol&lt;/a&gt;), attaches tags (like &lt;code&gt;['p', state.walletPubkey]&lt;/code&gt;), specifies the creation time (&lt;code&gt;DateTime.now()&lt;/code&gt;), and includes the &lt;code&gt;KeyPairs&lt;/code&gt; for encryption (with the private key).&lt;/p&gt;

&lt;p&gt;Finally, locate &lt;code&gt;// TODO: Send the event to relays with a timeout&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_nwc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;relaysService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendEventToRelays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;timeout:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;seconds:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sends the constructed request (&lt;code&gt;Event&lt;/code&gt; object) to the Nostr relays.&lt;/p&gt;

&lt;p&gt;So the &lt;code&gt;_sentToRelay&lt;/code&gt; method encapsulates the process of encrypting a message, constructing an Event request object with encrypted content, and sending it to the Nostr relays through the NWC. This functionality is crucial for interacting securely with the Nostr network, facilitating actions like making payments, creating invoices, and receiving updates, while maintaining the privacy and integrity of the transmitted data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting a Lightning Wallet
&lt;/h2&gt;

&lt;p&gt;Let's run the project and connect a Lightning wallet. After the splash screen, you'll see a screen where the user needs to paste the connection URI of the Lightning wallet. This screen is located in &lt;code&gt;lib/routes/initial_walkthrough/initial_walkthrough_page.dart&lt;/code&gt;. Open it and follow these steps:&lt;/p&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Access NWCAccountCubit instance from context&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;cubit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;NWCAccountCubit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This retrieves the &lt;code&gt;NWCAccountCubit&lt;/code&gt; instance using &lt;code&gt;context.read&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Call the connect method on NWCAccountCubit&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;cubit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;connectionURI:&lt;/span&gt; &lt;span class="n"&gt;connectionURI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;type:&lt;/span&gt; &lt;span class="n"&gt;NWCConnectTypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nwc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we're calling &lt;code&gt;cubit.connect&lt;/code&gt; to initiate the connection process to the user's remote Lightning wallet using the provided &lt;code&gt;connectionURI&lt;/code&gt; and passing the type as &lt;code&gt;NWCConnectTypes.nwc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, locate &lt;code&gt;// TODO: Replace the current route with the home screen&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;navigator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pushReplacementNamed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the connection is successful (no exceptions thrown), it navigates to the '/' route, typically replacing the current route with a new one, which is the home page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Obtaining the Connection URI
&lt;/h2&gt;

&lt;p&gt;To get the connection URI, use Lightning wallets that support NWC, such as Mutiny and Alby. For this article, we'll use Alby.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://nwc.getalby.com/" rel="noopener noreferrer"&gt;NWC by Alby&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Log in with your Alby account.&lt;/li&gt;
&lt;li&gt;Click on "Connect app" and enter "NWC Test" as the name (you can use any name).&lt;/li&gt;
&lt;li&gt;Optionally, set a "Monthly budget"; we'll keep it at 100k sats.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F3r9ffg6%2Fss2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F3r9ffg6%2Fss2.png" alt="NWC Alby"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5.Click "Next" and then "Copy pairing secret".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FnCDLsv2%2Fss3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FnCDLsv2%2Fss3.png" alt="NWC Alby"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The connection URI will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nostr+walletconnect://69effe7b49a6dd5cf525bd0905917a5005ffe480b58eeb8e861418cf3ae760d9?relay=wss://relay.getalby.com/v1&amp;amp;secret=f488038d4e52a63e8e6f29a0be46e683c4e08b7550c2d76be9712b7da149a05a&amp;amp;lud16=aniketamborebitcoindev@getalby.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Understanding the Connection URI
&lt;/h3&gt;

&lt;p&gt;The connection URI generated by the wallet service consists of the following components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protocol&lt;/strong&gt;: The URI begins with &lt;code&gt;nostr+walletconnect://&lt;/code&gt;, indicating the use of the Nostr Wallet Connect protocol.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base Path (Hex-encoded Pubkey)&lt;/strong&gt;: This uniquely identifies the user's wallet within the protocol. It's crucial for establishing a secure connection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query String Parameters&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;relay&lt;/code&gt;: This parameter is required and specifies the URL of the relay where the wallet service is connected and will listen for events. Multiple relays can be listed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;secret&lt;/code&gt;: Also required, this is a randomly generated 32-byte hex encoded string. It's used by the client to sign events and encrypt payloads when communicating with the wallet service.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lud16&lt;/code&gt;: While optional, it's recommended as a Lightning address that clients can use to automatically set up the lud16 field.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;To proceed, let's hot restart your app. Paste the connection URI into the input field and click "Connect".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FQQbWqKf%2Fss4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FQQbWqKf%2Fss4.png" alt="Nostr Pay - Home screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After connecting, you may notice your balance displayed as 0 sats on the home page, as we haven't yet retrieved it from the wallet. Let's move on to retrieving the balance in the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command: get_balance
&lt;/h2&gt;

&lt;p&gt;To get the correct balance of the wallet, go to &lt;code&gt;lib/bloc/nwc_account/nwc_account_cubit.dart&lt;/code&gt;. Locate &lt;code&gt;// TODO: Define a message to request balance&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;balanceMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"method"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"get_balance"&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is one of the wallet commands &lt;a href="https://github.com/nostr-protocol/nips/blob/master/47.md#get_balance" rel="noopener noreferrer"&gt;defined in NIP47 for getting the current balance&lt;/a&gt; of the user's wallet.&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Call the _sentToRelay function to send the balance message&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;_sentToRelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;balanceMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we're calling the &lt;code&gt;_sentToRelay&lt;/code&gt; method with &lt;code&gt;balanceMessage&lt;/code&gt; as the parameter.&lt;/p&gt;

&lt;p&gt;We are now publishing a request event to the relay with the command &lt;code&gt;get_balance&lt;/code&gt;. When our wallet service receives this event, it will publish the result or response for us. To handle this, locate &lt;code&gt;// TODO: Handle get_balance result&lt;/code&gt; inside the &lt;code&gt;_initializeConnection()&lt;/code&gt; method and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get_balance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;balanceResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;result&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Get_Balance_Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;_walletBalanceController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;balanceResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'balance: &lt;/span&gt;&lt;span class="si"&gt;${balanceResult.balance}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the &lt;code&gt;resultType&lt;/code&gt; is &lt;code&gt;get_balance&lt;/code&gt;, it casts &lt;code&gt;content.result&lt;/code&gt; to &lt;code&gt;Get_Balance_Result&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It then adds &lt;code&gt;balanceResult&lt;/code&gt; to &lt;code&gt;_walletBalanceController&lt;/code&gt;, which is used to stream wallet balance changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, simply hot restart the application, and you will see the current balance of your Lightning wallet on the home screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F4SYBjwn%2Fss5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F4SYBjwn%2Fss5.png" alt="Nostr Pay - Home screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Formatting and Refreshing
&lt;/h3&gt;

&lt;p&gt;Let's format the balance shown on the home screen and add a method to refresh it. Go to &lt;code&gt;lib/routes/home/home_page.dart&lt;/code&gt;. Locate &lt;code&gt;// TODO: Read NWCAccountCubit instance from context&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;accountCubit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;NWCAccountCubit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, locate &lt;code&gt;// TODO: Call the refresh method on accountCubit to refresh data&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;accountCubit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;refresh&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;refresh()&lt;/code&gt; method simply calls the sync method inside &lt;code&gt;NWCAccountCubit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Format the balance using the formatBalance method on accountCubit&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;${accountCubit.formatBalance(state.balance)}&lt;/span&gt;&lt;span class="s"&gt; sats'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method formats the balance.&lt;/p&gt;

&lt;p&gt;Now, hot reload the app, and you will see the changes made to the balance on the home screen. You can also pull to refresh the balance of the wallet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F7nqpN4Y%2Fss6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2F7nqpN4Y%2Fss6.png" alt="Nostr Pay - Home screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we'll implement the &lt;code&gt;make_invoice&lt;/code&gt; functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command: make_invoice
&lt;/h2&gt;

&lt;p&gt;Let's head over to &lt;code&gt;lib/bloc/nwc_account/nwc_account_cubit.dart&lt;/code&gt; and take a look at the &lt;code&gt;makeInvoice&lt;/code&gt; method which is responsible for creating a new invoice. It takes an amount in satoshis and an optional description as parameters.&lt;/p&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Construct the request object for making an invoice&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;"method"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"make_invoice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"params"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"amount"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amountInSats&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// value in msats&lt;/span&gt;
    &lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// invoice's description, optional&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;req&lt;/code&gt; constructs the &lt;a href="https://github.com/nostr-protocol/nips/blob/master/47.md#make_invoice" rel="noopener noreferrer"&gt;&lt;code&gt;make_invoice&lt;/code&gt; command defined in NIP47&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;amount&lt;/code&gt;: The amount in millisatoshis (msats). It converts the provided amount in satoshis to msats by multiplying by 1000.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt;: Optional description for the invoice.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Send the request to the relay using _sentToRelay&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;_sentToRelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sends the constructed request to the relays using the &lt;code&gt;_sentToRelay&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Now, locate &lt;code&gt;// TODO: Handle make_invoice result&lt;/code&gt; inside the &lt;code&gt;_initializeConnection()&lt;/code&gt; method and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;make_invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;invoiceResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;result&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Make_Invoice_Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'invoice: &lt;/span&gt;&lt;span class="si"&gt;${invoiceResult.invoice}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;copyWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;resultType:&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;make_invoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;makeInvoiceResult:&lt;/span&gt; &lt;span class="n"&gt;invoiceResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When &lt;code&gt;resultType&lt;/code&gt; is &lt;code&gt;make_invoice&lt;/code&gt;, it casts &lt;code&gt;content.result&lt;/code&gt; to &lt;code&gt;Make_Invoice_Result&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It emits a new state with &lt;code&gt;makeInvoiceResult&lt;/code&gt; to notify listeners about the newly created invoice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, head over to &lt;code&gt;lib/routes/create_invoice/create_invoice_page.dart&lt;/code&gt; and look at the &lt;code&gt;_createInvoice()&lt;/code&gt; method, responsible for initiating the invoice creation process in &lt;code&gt;NWCAccountCubit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Access NWCAccountCubit instance from context&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;cubit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;NWCAccountCubit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This retrieves the &lt;code&gt;NWCAccountCubit&lt;/code&gt; instance.&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Call the makeInvoice method on NWCAccountCubit&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;cubit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeInvoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;amountInSats:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_amountController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;description:&lt;/span&gt; &lt;span class="n"&gt;_descriptionController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;makeInvoice&lt;/code&gt; is called on the cubit with the parsed amount and description from user inputs.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;CreateInvoicePage&lt;/code&gt;, when the user clicks on "Create Invoice" and supplies the amount and description, the &lt;code&gt;makeInvoice&lt;/code&gt; method is invoked. The response handling is done through a listener.&lt;/p&gt;

&lt;p&gt;Now, let's move on to handling the response and errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listener in &lt;code&gt;create_invoice_page.dart&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The listener reacts to state changes in &lt;code&gt;NWCAccountCubit&lt;/code&gt;, specifically handling the results of making an invoice or encountering an error.&lt;/p&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Handle the case when the result type is 'make_invoice' and the makeInvoiceResult is not null&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="n"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;make_invoice&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeInvoiceResult&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;navigator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Navigator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;navigator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;popUntil&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 3&lt;/span&gt;
  &lt;span class="c1"&gt;// Navigate to InvoiceQrPage with the makeInvoiceResult.&lt;/span&gt;
  &lt;span class="n"&gt;navigator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;MaterialPageRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;InvoiceQrPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;makeInvoiceResult:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeInvoiceResult&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It checks if &lt;code&gt;resultType&lt;/code&gt; is &lt;code&gt;make_invoice&lt;/code&gt; and &lt;code&gt;makeInvoiceResult&lt;/code&gt; is not null.&lt;/li&gt;
&lt;li&gt;If conditions are met, it pops routes until the root ("/") route (home screen).&lt;/li&gt;
&lt;li&gt;Then, it pushes a new route to display &lt;code&gt;InvoiceQrPage&lt;/code&gt;, passing &lt;code&gt;makeInvoiceResult&lt;/code&gt; to it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Handle the case when the result type is 'error' and the nwcErrorResponse is not null&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nwcErrorResponse&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nwcErrorResponse&lt;/span&gt;&lt;span class="o"&gt;!.&lt;/span&gt;&lt;span class="na"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// 3&lt;/span&gt;
  &lt;span class="n"&gt;showToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;type:&lt;/span&gt; &lt;span class="n"&gt;ToastificationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It checks if &lt;code&gt;resultType&lt;/code&gt; is error and &lt;code&gt;nwcErrorResponse&lt;/code&gt; is not null.&lt;/li&gt;
&lt;li&gt;If conditions are met, it extracts the error message from &lt;code&gt;nwcErrorResponse&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Displays the error message as a toast notification using &lt;code&gt;showToast&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Handling Errors in &lt;code&gt;NWCAccountCubit&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;We need to handle error results in &lt;code&gt;NWCAccountCubit&lt;/code&gt;. Head over to &lt;code&gt;lib/bloc/nwc_account/nwc_account_cubit.dart&lt;/code&gt; and locate &lt;code&gt;// TODO: Handle error result&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;result&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;NWC_Error_Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;debugPrint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'error message: &lt;/span&gt;&lt;span class="si"&gt;${error.errorMessage}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;copyWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;resultType:&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;nwcErrorResponse:&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When &lt;code&gt;resultType&lt;/code&gt; is error, it casts &lt;code&gt;content.result&lt;/code&gt; to &lt;code&gt;NWC_Error_Result&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Emits a new state with &lt;code&gt;nwcErrorResponse&lt;/code&gt; to notify listeners about the encountered error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, hot restart the app. On the home page, click on "Receive", enter the amount and description, and click "Create Invoice". &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FZh9HdsY%2Fss7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FZh9HdsY%2Fss7.png" alt="Nostr Pay - Create invoice screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the invoice is generated, you will see the &lt;code&gt;InvoiceQrPage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FQjCXPVM%2Fss8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FQjCXPVM%2Fss8.png" alt="Nostr Pay - Invoice qr screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently, if someone pays this invoice, nothing happens. To handle this, we'll look into the &lt;code&gt;lookup_invoice&lt;/code&gt; command next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command: lookup_invoice
&lt;/h2&gt;

&lt;p&gt;Let's head back to &lt;code&gt;lib/bloc/nwc_account/nwc_account_cubit.dart&lt;/code&gt; and look at the &lt;code&gt;lookupInvoice&lt;/code&gt; method responsible for sending a request to check the status of a specific invoice.&lt;/p&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Construct the message to lookup the invoice&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;"method"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"lookup_invoice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"params"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"invoice"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;message&lt;/code&gt; constructs the &lt;a href="https://github.com/nostr-protocol/nips/blob/master/47.md#lookup_invoice" rel="noopener noreferrer"&gt;&lt;code&gt;lookup_invoice&lt;/code&gt; command as defined in NIP47&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;params&lt;/code&gt; key contains a map with the &lt;code&gt;invoice&lt;/code&gt; to be looked up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Send the lookup request to the relay using _sentToRelay&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;_sentToRelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sends the constructed request to the relays using the &lt;code&gt;_sentToRelay&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Now, locate &lt;code&gt;// TODO: Handle lookup_invoice result&lt;/code&gt; inside the &lt;code&gt;_initializeConnection()&lt;/code&gt; method and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookup_invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 1&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;result&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Lookup_Invoice_Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;copyWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;resultType:&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookup_invoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;lookupInvoiceResult:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When &lt;code&gt;resultType&lt;/code&gt; is &lt;code&gt;lookup_invoice&lt;/code&gt;, it casts &lt;code&gt;content.result&lt;/code&gt; to &lt;code&gt;Lookup_Invoice_Result&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Emits a new state with updated &lt;code&gt;lookupInvoiceResult&lt;/code&gt; to notify listeners about the invoice status.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next, head over to &lt;code&gt;lib/routes/invoice_qr/invoice_qr_page.dart&lt;/code&gt;. This page displays a QR code for the generated invoice and periodically checks if the invoice has been paid.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inside &lt;code&gt;_startPolling()&lt;/code&gt; method
&lt;/h3&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Access NWCAccountCubit instance from context&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;cubit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;NWCAccountCubit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This retrieves the &lt;code&gt;NWCAccountCubit&lt;/code&gt; instance.&lt;/p&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Call the lookupInvoice method on NWCAccountCubit with the invoice ID&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;cubit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookupInvoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeInvoiceResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;lookupInvoice&lt;/code&gt; is called on the cubit with the invoice ID from &lt;code&gt;widget.makeInvoiceResult&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listener in &lt;code&gt;invoice_qr_page.dart&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The listener listens for changes in &lt;code&gt;NWCAccountCubit&lt;/code&gt; state and reacts based on the type of result received.&lt;/p&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Handle the case when the result type is 'lookup_invoice' and the result is not null&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookup_invoice&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;isPaid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;settledAt&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isPaid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 3&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;navigator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Navigator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;navigator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;popUntil&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;navigator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;MaterialPageRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;SuccessPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;'Payment Received Successfully'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;description:&lt;/span&gt;
              &lt;span class="s"&gt;'Congratulations! You have successfully received sats from the sender.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It checks if &lt;code&gt;resultType&lt;/code&gt; is &lt;code&gt;lookup_invoice&lt;/code&gt; and &lt;code&gt;result&lt;/code&gt; is not null.&lt;/li&gt;
&lt;li&gt;Checks if &lt;code&gt;settledAt&lt;/code&gt; field in the result is not null, indicating that the invoice has been paid.&lt;/li&gt;
&lt;li&gt;If paid, pops routes until root ("/") route and navigates to &lt;code&gt;SuccessPage&lt;/code&gt; with a success message.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Handle the case when the result type is 'error' and the nwcErrorResponse is not null&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nwcErrorResponse&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nwcErrorResponse&lt;/span&gt;&lt;span class="o"&gt;!.&lt;/span&gt;&lt;span class="na"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="n"&gt;showToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;type:&lt;/span&gt; &lt;span class="n"&gt;ToastificationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It checks if &lt;code&gt;resultType&lt;/code&gt; is error and &lt;code&gt;nwcErrorResponse&lt;/code&gt; is not null.&lt;/li&gt;
&lt;li&gt;If conditions are met, it shows a toast notification with the error message.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That completes the &lt;code&gt;lookup_invoice&lt;/code&gt; command implementation. Now, hot restart the app, create an invoice, and try paying it. You'll see the &lt;code&gt;lookup_invoice&lt;/code&gt; command in action, navigating to the &lt;code&gt;SuccessPage&lt;/code&gt; upon successful payment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2Fzx09n7C%2Fss9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2Fzx09n7C%2Fss9.png" alt="Nostr Pay - Success Receive screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We've covered &lt;code&gt;get_balance&lt;/code&gt;, &lt;code&gt;make_invoice&lt;/code&gt;, and &lt;code&gt;lookup_invoice&lt;/code&gt;. Let's proceed to the final command of this article: &lt;code&gt;pay_invoice&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command: pay_invoice
&lt;/h2&gt;

&lt;p&gt;For the final command, head over to &lt;code&gt;lib/bloc/nwc_account/nwc_account_cubit.dart&lt;/code&gt; and look at the &lt;code&gt;payInvoice&lt;/code&gt; method which is responsible for paying a specific invoice provided by the user.&lt;/p&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Construct the message to pay the invoice&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;"method"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"pay_invoice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"params"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"invoice"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;message&lt;/code&gt; constructs the &lt;a href="https://github.com/nostr-protocol/nips/blob/master/47.md#pay_invoice" rel="noopener noreferrer"&gt;&lt;code&gt;pay_invoice&lt;/code&gt; command as defined in NIP47&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;params&lt;/code&gt; key contains a map with the &lt;code&gt;invoice&lt;/code&gt; to be paid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, locate &lt;code&gt;// TODO: Send the payment request to the relay using _sentToRelay&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;_sentToRelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sends the constructed request to the relays using the &lt;code&gt;_sentToRelay&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Now, locate &lt;code&gt;// TODO: Handle pay_invoice result&lt;/code&gt; inside the &lt;code&gt;_initializeConnection()&lt;/code&gt; method and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resultType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pay_invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 1&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;invoiceResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;result&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Pay_Invoice_Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="n"&gt;_paymentResultStreamController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;NWCPaymentResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;resultType:&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pay_invoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;payInvoiceResult:&lt;/span&gt; &lt;span class="n"&gt;invoiceResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// 3&lt;/span&gt;
  &lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;copyWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;resultType:&lt;/span&gt; &lt;span class="n"&gt;NWCResultType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pay_invoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;payInvoiceResult:&lt;/span&gt; &lt;span class="n"&gt;invoiceResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When &lt;code&gt;resultType&lt;/code&gt; is &lt;code&gt;pay_invoice&lt;/code&gt;, it casts &lt;code&gt;content.result&lt;/code&gt; to &lt;code&gt;Pay_Invoice_Result&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Adds a new payment result to &lt;code&gt;_paymentResultStreamController&lt;/code&gt; to stream to listeners.&lt;/li&gt;
&lt;li&gt;Emits a new state with updated &lt;code&gt;payInvoiceResult&lt;/code&gt; to reflect the payment operation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, let's integrate this into the UI flow for paying an invoice.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;PaymentRequestDialog&lt;/code&gt; in &lt;code&gt;payment_dialogs/payment_request_dialog.dart&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This dialog handles the confirmation of paying an invoice after decoding it. Locate &lt;code&gt;// TODO: Call the payInvoice method on accountCubit with the invoice bolt11&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nl"&gt;paymentFunc:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;accountCubit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;payInvoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bolt11&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;payInvoice&lt;/code&gt; method is called on &lt;code&gt;accountCubit&lt;/code&gt; with the &lt;code&gt;bolt11&lt;/code&gt; invoice string from &lt;code&gt;widget.invoice&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using &lt;code&gt;payInvoice&lt;/code&gt; in UI Flow
&lt;/h3&gt;

&lt;p&gt;From the home screen, when the user clicks on "Send", they are taken to the &lt;code&gt;PayInvoicePage&lt;/code&gt;. After pasting the invoice there and clicking on "Pay Invoice" button, the invoice is decoded, and a confirmation dialog (&lt;code&gt;PaymentRequestDialog&lt;/code&gt;) is shown to the user.&lt;/p&gt;

&lt;p&gt;If the user clicks "Yes" in the &lt;code&gt;PaymentRequestDialog&lt;/code&gt;, the &lt;code&gt;payInvoice&lt;/code&gt; method we just implemented is called to initiate the payment process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing the Flow
&lt;/h3&gt;

&lt;p&gt;Hot restart the app. Click on "Send" on the home page, paste an invoice from a different wallet, and click "Pay Invoice". &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FTPS7MGs%2Fss10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FTPS7MGs%2Fss10.png" alt="Nostr Pay - Enter payment info"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;PaymentRequestDialog&lt;/code&gt;, click "Yes".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FL8nMTBh%2Fss11.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FL8nMTBh%2Fss11.png" alt="Nostr Pay - Payment request dialog"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll see a &lt;code&gt;ProcessingPaymentDialog&lt;/code&gt; and after that, a success screen if the payment is successful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FQjdxqtZ%2Fss12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FQjdxqtZ%2Fss12.png" alt="Nostr Pay - Success send screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This completes the integration of the &lt;code&gt;pay_invoice&lt;/code&gt; command. Now you have a complete flow for creating, receiving, and paying invoices using the &lt;code&gt;NWCAccountCubit&lt;/code&gt; and handling the respective results and errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As we come to the end of our journey exploring Nostr wallet connect, I want to express my heartfelt thanks to the developers and the vibrant community driving innovations in Nostr, NWC, and the Lightning Network space. Your dedication and expertise have made it straightforward for developers like me to integrate Lightning Network capabilities into our apps.&lt;/p&gt;

&lt;p&gt;As we continue to explore Lightning Network features in our apps, remember that this technology marks just the beginning of a transformative era in Bitcoin's scalability.&lt;/p&gt;

&lt;p&gt;If you have any questions or wish to share your experiences, please feel free to reach out to me on &lt;a href="https://twitter.com/Anipy1" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://snort.social/p/npub1clqc0wnk2vk42u35jzhc3emd64c0u4g6y3su4x44g26s8waj2pzskyrp9x" rel="noopener noreferrer"&gt;Nostr&lt;/a&gt;, or &lt;a href="https://www.linkedin.com/in/aniketambore/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for joining me on this journey. ⚡🌊  &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Clipboard Monitoring for Bitcoin Addresses in Flutter</title>
      <dc:creator>Aniket Ambore</dc:creator>
      <pubDate>Sun, 31 Dec 2023 13:00:25 +0000</pubDate>
      <link>https://dev.to/anipy/clipboard-monitoring-for-bitcoin-addresses-in-flutter-1hdl</link>
      <guid>https://dev.to/anipy/clipboard-monitoring-for-bitcoin-addresses-in-flutter-1hdl</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hello, and welcome to this tutorial article! In this article, I'll guide you through the process of implementing clipboard monitoring in a Flutter app. You'll learn how to watch the device clipboard and take actions based on the clipboard data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UIbn2Ljj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://i.ibb.co/T4v4j69/Clipboard-Monitoring-for-Bitcoin-Addresses-in-Flutter.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UIbn2Ljj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://i.ibb.co/T4v4j69/Clipboard-Monitoring-for-Bitcoin-Addresses-in-Flutter.gif" alt="Demo" width="600" height="1333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Case
&lt;/h2&gt;

&lt;p&gt;Have you ever wondered how Bitcoin wallets detect copied addresses and prompt you when you open another wallet? We'll be implementing exactly that functionality in this article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KOKLj6Tl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/6gvyBVH/blue-wallet-clipboard-dialog.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KOKLj6Tl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/6gvyBVH/blue-wallet-clipboard-dialog.jpg" alt="Clipboard Dialog" width="800" height="1778"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what you'll learn to implement in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Let's begin!&lt;/p&gt;

&lt;p&gt;First, create a new Flutter project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter create watching_clipboard_demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the project, open the &lt;code&gt;pubspec.yaml&lt;/code&gt; file and add the following dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;sdk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter&lt;/span&gt;
  &lt;span class="na"&gt;clipboard_watcher&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.2.0&lt;/span&gt;
  &lt;span class="na"&gt;rxdart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.27.7&lt;/span&gt;
  &lt;span class="na"&gt;shared_preferences&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.2.2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what each dependency helps you with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;clipboard_watcher&lt;/code&gt;: A Flutter plugin for listening to clipboard changes. Useful for detecting changes in the clipboard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;rxdart&lt;/code&gt;: RxDart is a reactive functional programming library for Dart. It provides a set of reactive extensions for Dart streams.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;shared_preferences&lt;/code&gt;: Shared Preferences plugin for Flutter, providing a persistent key-value store for simple data storage.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After adding the dependencies, run &lt;code&gt;flutter pub get&lt;/code&gt; to fetch them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clipboard Manager Implementation:
&lt;/h2&gt;

&lt;p&gt;Now, let's create a new file inside the &lt;code&gt;lib&lt;/code&gt; folder named &lt;code&gt;clipboard_manager.dart&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:clipboard_watcher/clipboard_watcher.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/services.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:rxdart/rxdart.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:shared_preferences/shared_preferences.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClipboardManager&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ClipboardListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;_lastFromAppClip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 3&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;LAST_CLIPPING_PREFERENCES_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"lastClipping"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;LAST_FROM_APP_CLIPPING_PREFERENCES_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="s"&gt;"lastFromAppClipping"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// 4&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_clipboardController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
  &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;clipboardStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_clipboardController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;_lastFromAppClip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;ClipboardManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'[+] Initiating ClipboardManager'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 5&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sharedPreferences&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SharedPreferences&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// 6&lt;/span&gt;
    &lt;span class="n"&gt;sharedPreferences&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;preferences&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// 7&lt;/span&gt;
      &lt;span class="n"&gt;_lastFromAppClip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="n"&gt;preferences&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LAST_FROM_APP_CLIPPING_PREFERENCES_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// 8&lt;/span&gt;
      &lt;span class="n"&gt;_clipboardController&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preferences&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LAST_CLIPPING_PREFERENCES_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[+] Last clipping: &lt;/span&gt;&lt;span class="si"&gt;$_lastFromAppClip&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// 9&lt;/span&gt;
      &lt;span class="n"&gt;fetchClipboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preferences&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="c1"&gt;// 10&lt;/span&gt;
    &lt;span class="n"&gt;clipboardWatcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// 11&lt;/span&gt;
    &lt;span class="n"&gt;clipboardWatcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;fetchClipboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SharedPreferences&lt;/span&gt; &lt;span class="n"&gt;preferences&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Implement fetchClipboard&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;setClipboardText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Implement setClipboardText&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 12&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;onClipboardChanged&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[+] Clipboard changed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// 13&lt;/span&gt;
    &lt;span class="n"&gt;SharedPreferences&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;preferences&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;fetchClipboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preferences&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, we're performing the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;ClipboardManager&lt;/code&gt; class extends &lt;code&gt;ClipboardListener&lt;/code&gt; to capture clipboard change events.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_lastFromAppClip&lt;/code&gt; stores the last clipboard content copied from inside our app.&lt;/li&gt;
&lt;li&gt;Keys used for storing and retrieving clipboard content in SharedPreferences.&lt;/li&gt;
&lt;li&gt;Controller for managing clipboard content stream.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Inside the &lt;code&gt;ClipboardManager&lt;/code&gt; constructor, we're:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retriving the &lt;code&gt;SharedPreferences&lt;/code&gt; instance.&lt;/li&gt;
&lt;li&gt;Handling the &lt;code&gt;SharedPreferences&lt;/code&gt; instance when available.&lt;/li&gt;
&lt;li&gt;Retrieving the last clipboard content copied from inside the app.&lt;/li&gt;
&lt;li&gt;Adding the last clipboard content to the stream.&lt;/li&gt;
&lt;li&gt;Fetch the clipboard content.&lt;/li&gt;
&lt;li&gt;Adding &lt;code&gt;ClipboardListener&lt;/code&gt; to detect clipboard changes.&lt;/li&gt;
&lt;li&gt;Starting to listen for clipboard changes.&lt;/li&gt;
&lt;li&gt;Overriding &lt;code&gt;onClipboardChanged&lt;/code&gt; method to handle clipboard change events.&lt;/li&gt;
&lt;li&gt;Getting the &lt;code&gt;SharedPreferences&lt;/code&gt; instance and fetching clipboard content.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One thing I want you to understand is the approach behind &lt;code&gt;_lastFromAppClip&lt;/code&gt;, &lt;code&gt;LAST_CLIPPING_PREFERENCES_KEY&lt;/code&gt;, and &lt;code&gt;LAST_FROM_APP_CLIPPING_PREFERENCES_KEY&lt;/code&gt;. When the user copies a bitcoin address from inside our app (referred to as "&lt;em&gt;from app clipping&lt;/em&gt;"), we don't want to show the Clipboard dialog because that content is copied within the app. Displaying the dialog for content copied within the app is considered a bug.&lt;/p&gt;

&lt;p&gt;That's why in the &lt;code&gt;clipboardStream&lt;/code&gt;, we're discarding all elements that are not equal to the content copied within the app (&lt;code&gt;_lastFromAppClip&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Let's move on to implement &lt;code&gt;fetchClipboard&lt;/code&gt; method by locating &lt;code&gt;// TODO: Implement fetchClipboard&lt;/code&gt; and replacing it with the following code as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fetchClipboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SharedPreferences&lt;/span&gt; &lt;span class="n"&gt;preferences&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[+] Fetching clipboard"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// 1&lt;/span&gt;
    &lt;span class="n"&gt;Clipboard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'text/plain'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;clipboardData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// 2&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clipboardData&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'[+] Clipboard text: &lt;/span&gt;&lt;span class="si"&gt;$text&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// 3&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 4&lt;/span&gt;
        &lt;span class="n"&gt;_clipboardController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// 5&lt;/span&gt;
        &lt;span class="n"&gt;preferences&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LAST_CLIPPING_PREFERENCES_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above method retrieves the current content of the clipboard using the &lt;code&gt;Clipboard.getData&lt;/code&gt; method from the &lt;code&gt;flutter/services.dart&lt;/code&gt; package. If the clipboard contains text data, it is added to the &lt;code&gt;_clipboardController&lt;/code&gt; stream and stored in &lt;code&gt;SharedPreferences&lt;/code&gt; for future reference. Here we're:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using the &lt;code&gt;Clipboard.getData&lt;/code&gt; method to retrieve clipboard data of type 'text/plain'.&lt;/li&gt;
&lt;li&gt;Extracting the text content from the clipboard data.&lt;/li&gt;
&lt;li&gt;Checking if the text content is not null.&lt;/li&gt;
&lt;li&gt;Adding the text content to the &lt;code&gt;_clipboardController&lt;/code&gt; stream.&lt;/li&gt;
&lt;li&gt;Storing the text content in &lt;code&gt;SharedPreferences&lt;/code&gt; under the specified key.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Main App Implementation
&lt;/h2&gt;

&lt;p&gt;Now, let's move on to the &lt;code&gt;main.dart&lt;/code&gt; file and replace the default counter app Flutter example with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:watching_clipboard_demo/clipboard_manager.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;WidgetsFlutterBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ensureInitialized&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// 1&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;clipboardManager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ClipboardManager&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;MaterialApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;home:&lt;/span&gt; &lt;span class="n"&gt;ClipboardWatcherApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;clipboardManager:&lt;/span&gt; &lt;span class="n"&gt;clipboardManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClipboardWatcherApp&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;ClipboardWatcherApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clipboardManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;ClipboardManager&lt;/span&gt; &lt;span class="n"&gt;clipboardManager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ClipboardWatcherApp&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_ClipboardWatcherAppState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_ClipboardWatcherAppState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ClipboardWatcherApp&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;copiedBitcoinAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// 3&lt;/span&gt;
    &lt;span class="n"&gt;_startClipboardWatching&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 4&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;_startClipboardWatching&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Implement _startClipboardWatching&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 5&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isBitcoinAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Implement isBitcoinAddress&lt;/span&gt;
    &lt;span class="c1"&gt;// This method should perform Bitcoin address validation.&lt;/span&gt;
    &lt;span class="c1"&gt;// Return true if the address is a valid Bitcoin address, false otherwise.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 6&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;_showBitcoinAddressDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;bitcoinAddress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;showDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;context:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;AlertDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Clipboard"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nl"&gt;content:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="s"&gt;"You have a Bitcoin address on your clipboard. Would you like to use it for a transaction?"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nl"&gt;actions:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;TextButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Navigator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cancel"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;TextButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;copiedBitcoinAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bitcoinAddress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;Navigator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Close the dialog&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Continue"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 7&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;padding:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
              &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currency_bitcoin_outlined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nl"&gt;size:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;copiedBitcoinAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="nl"&gt;fontSize:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="nl"&gt;fontWeight:&lt;/span&gt; &lt;span class="n"&gt;FontWeight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;w600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We initialize &lt;code&gt;ClipboardManager&lt;/code&gt; to listen for clipboard changes.&lt;/li&gt;
&lt;li&gt;A variable to store the last copied Bitcoin address.&lt;/li&gt;
&lt;li&gt;We start watching the clipboard when the app starts.&lt;/li&gt;
&lt;li&gt;A method to start watching the clipboard for Bitcoin addresses.&lt;/li&gt;
&lt;li&gt;A method to check if the given string is a Bitcoin address.&lt;/li&gt;
&lt;li&gt;A method to show a dialog when a Bitcoin address is detected in the clipboard.&lt;/li&gt;
&lt;li&gt;We build the main screen with a Bitcoin icon and the copied Bitcoin address.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, let's run the app and observe the simple screen with the Bitcoin icon in the center.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4zpD7XvC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/z5D5N8F/Screenshot-1704017539.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4zpD7XvC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/z5D5N8F/Screenshot-1704017539.png" alt="Main Screen" width="800" height="1422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Address Validation
&lt;/h3&gt;

&lt;p&gt;Now, let's implement the &lt;code&gt;isBitcoinAddress&lt;/code&gt; method in &lt;code&gt;main.dart&lt;/code&gt; by locating &lt;code&gt;// TODO: Implement isBitcoinAddress&lt;/code&gt; and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;isBitcoinAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Implement your Bitcoin address validation logic here&lt;/span&gt;
    &lt;span class="c1"&gt;// Check if the provided address matches the Bitcoin address pattern&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'bc1'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this &lt;code&gt;isBitcoinAddress&lt;/code&gt; method, I'm checking if the address starts with &lt;code&gt;bc1&lt;/code&gt; to determine if it's in segwit or bech32 address format. However, you can use appropriate regex or a Bitcoin package for a more comprehensive validation based on your specific requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clipboard Watching
&lt;/h3&gt;

&lt;p&gt;Next, let's implement the &lt;code&gt;_startClipboardWatching&lt;/code&gt; method by locating &lt;code&gt;// TODO: Implement _startClipboardWatching&lt;/code&gt; and replacing it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;_startClipboardWatching&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[+] _watchingIncoming"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 1&lt;/span&gt;
    &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clipboardManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clipboardStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;distinct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// 2&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isBitcoinAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 3&lt;/span&gt;
        &lt;span class="n"&gt;_showBitcoinAddressDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;_startClipboardWatching&lt;/code&gt; method starts watching the clipboard for Bitcoin addresses. Here's a breakdown:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Subscribe to the clipboard stream provided by the &lt;code&gt;ClipboardManager&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;distinct()&lt;/code&gt; to filter out consecutive identical clipboard content.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;skip(1)&lt;/code&gt; to skip the initial content when the app starts.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;listen()&lt;/code&gt; to react to changes in the clipboard content.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Checking if the clipboard content is a Bitcoin address. &lt;/li&gt;
&lt;li&gt;If it is a Bitcoin address, show a dialog to the user.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You maybe thinking why I used &lt;code&gt;skip(1)&lt;/code&gt; here?&lt;/p&gt;

&lt;p&gt;Well, the purpose of &lt;code&gt;skip(1)&lt;/code&gt; operator is used to skip the initial value emitted by the clipboard stream when the app starts. And the reason of using &lt;code&gt;skip(1)&lt;/code&gt; is because when the app initializes, the clipboard may already contain some content. If the app doesn't skip the initial value, it might trigger unnecessary actions based on the current clipboard content at the app's launch. By using &lt;code&gt;skip(1)&lt;/code&gt;, we ensure that the app only react to changes in the clipboard content after the app has started.&lt;/p&gt;

&lt;p&gt;Great! With this, we're almost done. Now, run the app again. Copy a Bitcoin address from another app, then open the app. You will see the dialog as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2h2iaMjl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/YPgVs6d/Screenshot-1704017829.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2h2iaMjl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/YPgVs6d/Screenshot-1704017829.png" alt="Clipboard Dialog" width="800" height="1422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on "Continue" in the dialog, and the main screen will update accordingly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0BUMzLH6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/27TR4yC/Screenshot-1704017852.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0BUMzLH6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/27TR4yC/Screenshot-1704017852.png" alt="Main Screen Updated" width="800" height="1422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9gFmZ7ep--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://i.ibb.co/2dbZVX1/watching-clipboard-demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9gFmZ7ep--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://i.ibb.co/2dbZVX1/watching-clipboard-demo.gif" alt="Final Demo" width="600" height="1333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Homework and Conclusion
&lt;/h2&gt;

&lt;p&gt;Fantastic! Everything is in place. The only thing left is the setClipboardText method of ClipboardManager, and that is your homework. Try to implement it. Additionally, create a simple widget on the main screen displaying a hardcoded Bitcoin address and a copy button. Clicking on the copy button should copy the Bitcoin address to the clipboard. If the dialog is shown, your implementation is incorrect. If the dialog is not shown, everything is right.&lt;/p&gt;

&lt;p&gt;The homework solution will be available on the GitHub repo of this article &lt;a href="https://github.com/aniketambore/bitcoin_tutorials_by_anipy/tree/main/watching_clipboard_demo"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have questions or want to connect and share your experiences, feel free to reach out to me on &lt;a href="https://twitter.com/Anipy1"&gt;Twitter&lt;/a&gt;, &lt;a href="https://snort.social/p/npub1clqc0wnk2vk42u35jzhc3emd64c0u4g6y3su4x44g26s8waj2pzskyrp9x"&gt;Nostr&lt;/a&gt;, or &lt;a href="https://www.linkedin.com/in/aniketambore/"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for joining me. ⚡🌊&lt;/p&gt;

</description>
      <category>bitcoin</category>
      <category>flutter</category>
    </item>
    <item>
      <title>Tutorial: How to develop a Non-Custodial Bitcoin Lightning Wallet using Flutter and LDK?</title>
      <dc:creator>Aniket Ambore</dc:creator>
      <pubDate>Sun, 15 Oct 2023 15:24:00 +0000</pubDate>
      <link>https://dev.to/anipy/tutorial-how-to-develop-a-non-custodial-bitcoin-lightning-wallet-using-flutter-and-ldk-13ik</link>
      <guid>https://dev.to/anipy/tutorial-how-to-develop-a-non-custodial-bitcoin-lightning-wallet-using-flutter-and-ldk-13ik</guid>
      <description>&lt;p&gt;Hello everyone! My name is Aniket (aka Anipy) and in this tutorial, I'm going to show you how to create your very own Non-Custodial Bitcoin Lightning wallet using Flutter and the Lightning Development Kit (LDK). It all began for me when I finished reading "Mastering the Lightning Network" book. As a little side project, I decided to develop a non-custodial Bitcoin Lightning wallet, and here's what I've learned and developed along the way.&lt;/p&gt;

&lt;p&gt;In this tutorial, I'll share my experiences and provide answers to some of the questions and challenges I encountered while developing the wallet. I received plenty of help from the friendly LDK team developers on their Discord channel, and I'll do my best to explain everything in a straightforward manner. Just a heads up, we won't be diving too deep into UI development or Flutter here; our main focus will be on implementing a Lightning wallet in Flutter with LDK.&lt;/p&gt;

&lt;p&gt;If you're already familiar with the Lightning Network, Lightning nodes, and Lightning wallets, feel free to jump right into the "Getting Started" section below. For those of you looking for a quick refresher or wanting to explore this fascinating technology from the ground up, read on for a brief overview.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Lightning Network?
&lt;/h2&gt;

&lt;p&gt;Let's discuss the Lightning Network in simple terms. It's like a protocol built on top of Bitcoin that makes transactions faster, more private, and scalable.&lt;/p&gt;

&lt;p&gt;In 2015, Joseph Poon and Thaddeus Dryja proposed the Lightning Network to address Bitcoin's scalability issue.&lt;/p&gt;

&lt;p&gt;Think of the Lightning Network as a helpful tool that acts as a second layer technology by enabling off-chain transactions, it reduces the load on the main bitcoin blockchain and allow faster and more cost-effective microtransactions.&lt;/p&gt;

&lt;p&gt;Users initially load Bitcoin onto the Lightning Network. They settle on-chain only when they open or close channels (we'll cover this shortly). After that, payments within an open channel can be almost instant, without requiring confirmation from Bitcoin blocks.&lt;/p&gt;

&lt;p&gt;The Lightning Network has some cool features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Payments on the Lightning Network do not require waiting for block confirmations.&lt;/li&gt;
&lt;li&gt;Lightning Network payments are transmitted between pairs of nodes, offering enhanced privacy compared to on-chain transactions.&lt;/li&gt;
&lt;li&gt;Unlike Bitcoin network transactions, Lightning Network payments do not need permanent storage, reducing resource usage and cost.&lt;/li&gt;
&lt;li&gt;Nodes involved in routing payments are aware only of their predecessor and successor in the payment route.&lt;/li&gt;
&lt;li&gt;The Lightning Network utilizes real bitcoin, maintaining user custody and full control over funds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, remember that the Lightning Network is not a separate token or coin; it's built on top of Bitcoin. In the next section we'll talk about Lightning node.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Lightning Node?
&lt;/h2&gt;

&lt;p&gt;The Lightning Network operates through software apps that implement the Lightning Network protocol and most of these apps follow common standards outlined in the &lt;a href="https://github.com/lightning/bolts/tree/master"&gt;BOLTs&lt;/a&gt; specification.&lt;/p&gt;

&lt;p&gt;A Lightning Network node (LN node) is a piece of software with these key characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It serves as a wallet for payments on both the Lightning and Bitcoin network.&lt;/li&gt;
&lt;li&gt;It communicates directly with other nodes, forming the network through peer-to-peer connections.&lt;/li&gt;
&lt;li&gt;It needs access to the Bitcoin blockchain for payment security.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Users have the highest level of control when they run their own Bitcoin node and Lightning node. However, Lightning nodes can also use a lightweight Bitcoin client to interact with the Bitcoin blockchain.&lt;/p&gt;

&lt;p&gt;Now in the next section let's talk about Lightning wallet.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Lightning Wallet?
&lt;/h2&gt;

&lt;p&gt;The term "Lightning wallet" can be a bit unclear because it can refer to a combination of various components with some user interface. The most common components found in Lightning wallet software include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A keystore that holds secrets, such as wallet mnemonic.&lt;/li&gt;
&lt;li&gt;An LN node (Lightning node) that communicates on the peer-to-peer network, as we discussed earlier.&lt;/li&gt;
&lt;li&gt;A Bitcoin node that stores blockchain data and communicates with other Bitcoin nodes&lt;/li&gt;
&lt;li&gt;A database that maps out nodes and channels announced on the Lightning Network.&lt;/li&gt;
&lt;li&gt;A channel manager that can open and close LN channels&lt;/li&gt;
&lt;li&gt;A close-up system that can find a path of connected channels from payment source to payment destination.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Lightning wallet may contain all of these functions, acting as a "full" wallet, with no reliance on any third-party services. Or one or more of these components may rely (partially or entirely) on third-party services that mediate those functions.&lt;/p&gt;

&lt;p&gt;A key distinction (pun intended) is whether the keystore function is internal or outsourced. In blockchains, control of keys determines custody of funds, as memorialized by the phrase "&lt;em&gt;your keys, your coins; not your keys, not your coins&lt;/em&gt;".&lt;/p&gt;

&lt;p&gt;Custodial wallets outsource key management, while noncustodial wallets put you in control of your own keys.&lt;/p&gt;

&lt;p&gt;The wallet you'll learn to create in this tutorial is a noncustodial wallet. This means the user of our wallet will have full control over their keys.&lt;/p&gt;

&lt;p&gt;The term "noncustodial wallet" implies that the keystore is local and under the user's control. However, some of the other wallet components may or may not rely on trusted third parties.&lt;/p&gt;

&lt;p&gt;Remember that, control over keys is a critical consideration when choosing a Lightning wallet.&lt;/p&gt;

&lt;p&gt;Now that you understand the Lightning Network and its key parts, let's jump in and start making your very own Lightning wallet. Get ready for an exciting journey!&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Before we get our hands dirty with code, let's kick things off by grabbing the "&lt;strong&gt;starter&lt;/strong&gt;" project for this tutorial. Just copy and paste the following command into your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;-b&lt;/span&gt; starter &lt;span class="nt"&gt;--single-branch&lt;/span&gt; https://github.com/aniketambore/bijli_ln_wallet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will get you the "&lt;strong&gt;starter&lt;/strong&gt;" project in no time and will save your time.&lt;/p&gt;

&lt;p&gt;Feeling the excitement? Great! Now, fire up your favorite code editor, whether it's VS Code or Android Studio. After that, run &lt;code&gt;flutter pub get&lt;/code&gt; to set things up, and then launch the app. Right now, it's a straightforward UI project, but we'll soon weave in some Lightning Network magic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z7O1Z9Cd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/5LZd7RH/wallet-creation-ss-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z7O1Z9Cd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/5LZd7RH/wallet-creation-ss-1.png" alt="Wallet Creation Screen" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project files
&lt;/h2&gt;

&lt;p&gt;There are some files in the &lt;strong&gt;starter&lt;/strong&gt; project to help you out. Before you learn how to develop a non-custodial bitcoin lightning wallet, take a look at them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assets folder
&lt;/h3&gt;

&lt;p&gt;Inside the &lt;strong&gt;assets&lt;/strong&gt; directory, you'll find images that will be used to build your app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sQH7I7_v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/jwY0v67/assets-folder.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sQH7I7_v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/jwY0v67/assets-folder.png" alt="Assets Folder" width="346" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Folder Structure
&lt;/h2&gt;

&lt;p&gt;In the &lt;strong&gt;lib&lt;/strong&gt; directory, you'll notice various folders, each serving a specific purpose:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O9g5dqKy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/SBKfxXY/lib-folder.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O9g5dqKy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/SBKfxXY/lib-folder.png" alt="lib Folder" width="317" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Component Library Folder
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;lib/component_library&lt;/strong&gt; contains all the UI components that either are, or have the potential to be, reused across different screens.&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain Models Folder
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;lib/domain_models&lt;/strong&gt; contains all the model objects used in our app. These models define how data is structured and managed within the app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features Folder
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;lib/features&lt;/strong&gt; contains the core functionality of the app, following a &lt;em&gt;package-by-feature&lt;/em&gt; approach. It's where the magic happens.&lt;/p&gt;

&lt;p&gt;I consider a feature to be either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A screen&lt;/li&gt;
&lt;li&gt;A dialog that excutes I/O calls. The &lt;strong&gt;lib/features/send_offchain_dialog&lt;/strong&gt; falls into this category.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Wallet Repository Folder
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;lib/wallet_repository&lt;/strong&gt; is where the communication with the LDK (Lightning Development Kit) Node Flutter plugin happens. This repository coordinates data from different sources and keeps things running smoothly.&lt;/p&gt;

&lt;h2&gt;
  
  
  App libraries
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;starter&lt;/strong&gt; project comes with a set of useful libraries listed in &lt;code&gt;pubspec.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
  &lt;span class="s"&gt;bitcoin_ui_kit&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;git&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/aniketambore/bitcoinuikit-flutter.git&lt;/span&gt;
      &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alternative-implementation&lt;/span&gt;
  &lt;span class="na"&gt;bitcoin_icons&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.0.4&lt;/span&gt;
  &lt;span class="na"&gt;ldk_node&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.1.2&lt;/span&gt;
  &lt;span class="na"&gt;bolt11_decoder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.0.2&lt;/span&gt;
  &lt;span class="na"&gt;bip39&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.0.6&lt;/span&gt;
  &lt;span class="na"&gt;flutter_secure_storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^9.0.0&lt;/span&gt;
  &lt;span class="na"&gt;path_provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.0.12&lt;/span&gt;
  &lt;span class="na"&gt;qr_flutter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^4.1.0&lt;/span&gt;
  &lt;span class="na"&gt;share_plus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^7.1.0&lt;/span&gt;
  &lt;span class="na"&gt;another_flushbar&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.12.30&lt;/span&gt;
  &lt;span class="na"&gt;floating_action_bubble&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.1.4&lt;/span&gt;
  &lt;span class="na"&gt;equatable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.0.5&lt;/span&gt;
  &lt;span class="na"&gt;auto_size_text&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^3.0.0&lt;/span&gt;
  &lt;span class="na"&gt;routemaster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.0.1&lt;/span&gt;
  &lt;span class="na"&gt;flutter_bloc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^8.1.3&lt;/span&gt;
  &lt;span class="na"&gt;confetti&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.7.0&lt;/span&gt;
  &lt;span class="na"&gt;rxdart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.27.7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what they help you to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;bitcoin_ui_kit&lt;/code&gt;: This package offers helpful widgets and themes following the &lt;a href="https://bitcoin.design/guide/"&gt;Bitcoin design guide&lt;/a&gt;. It's like a design toolbox,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;bitcoin_icons&lt;/code&gt;: Use this package to easily access the collections of &lt;a href="https://bitcoinicons.com/"&gt;Bitcoin icons&lt;/a&gt; for your app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ldk_node&lt;/code&gt;: This package provides a simple interface for setting up and running a Lightning node with an integrated on-chain wallet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;bolt11_decoder&lt;/code&gt;: Use this package to decode BOLT11 invoices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;bip39&lt;/code&gt;: This package helps generate new mnemonic phrases. It's like a phrase generator.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;flutter_secure_storage&lt;/code&gt;: This package ensures secure storage capabilities for your app. It's your secret vault for mnemonic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;path_provider&lt;/code&gt;: This package helps you access the file system path on the device.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;qr_flutter&lt;/code&gt;: This package enables you to generate QR codes within your app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;share_plus&lt;/code&gt;: This package allows easy sharing of content from our app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;another_flushbar&lt;/code&gt;: This package provides customizable and user-friendly notifications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;floating_action_bubble&lt;/code&gt;: This package helps us to create floating action buttons with a bubble effect.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;equatable&lt;/code&gt;: This package simplifies equality comparisons for our Dart classes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;auto_size_text&lt;/code&gt;: This package automatically adjusts the text size to fit the available space.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;routemaster&lt;/code&gt;: This package offers a flexible routing system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;flutter_bloc&lt;/code&gt;: This package is used to implement the BLoC (Business Logic Component) design pattern in our app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;confetti&lt;/code&gt;: This package adds confetti animations to our app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;rxdart&lt;/code&gt;: This package extends the capabilities of Dart's Streams with reactive programming.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wallet Initialization
&lt;/h2&gt;

&lt;p&gt;In this step, we'll set up our wallet, starting with some crucial configurations. Open &lt;strong&gt;lib/wallet_repository/src/wallet_repository.dart&lt;/strong&gt; and follow these instructions:&lt;/p&gt;

&lt;h3&gt;
  
  
  Import the Necessary Packages
&lt;/h3&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Add imports here&lt;/code&gt; and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:ldk_node/ldk_node.dart'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:bip39/bip39.dart'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;bip39&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:path_provider/path_provider.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we're importing the &lt;code&gt;ldk_node&lt;/code&gt; plugin and &lt;code&gt;bip39&lt;/code&gt; and &lt;code&gt;path_provider&lt;/code&gt; package, giving alias "&lt;strong&gt;ldk&lt;/strong&gt;" and "&lt;strong&gt;bip39&lt;/strong&gt;" is for easier reference in your code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialize Wallet Configuration
&lt;/h3&gt;

&lt;p&gt;Move on to &lt;code&gt;// TODO: Initialize variables here&lt;/code&gt; and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// 1&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;LDK_NODE_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"LDK_NODE"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// 2&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;esploraURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://mempool.space/testnet/api"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// 3&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;network&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Network&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Testnet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// 4&lt;/span&gt;
  &lt;span class="kd"&gt;late&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Node&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we're defining configuration variables for LDK:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;LDK_NODE_DIR&lt;/code&gt;: Defines the directory where your LDK node's data will be stored.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;esploraURL&lt;/code&gt;: This URL points to a Bitcoin testnet server (specifically, mempool.space) used for indexing blockchain data quickly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;network&lt;/code&gt;: Indicates that the network being used is the Bitcoin testnet. Options avialable are [Bitcoin, Testnet, Signet, Regtest]&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ldkNode&lt;/code&gt;: The &lt;code&gt;ldkNode&lt;/code&gt; variable will hold the instance of the LDK node that will be set up below for interacting with the Lightning Network.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Generate a New Mnemonic
&lt;/h3&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Implement method to generate a new mnemonic&lt;/code&gt; and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;_generateMnemonic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;mnemonic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bip39&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generateMnemonic&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// 2&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mnemonic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, we're:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generating a new mnemonic using the &lt;code&gt;bip39&lt;/code&gt; package.&lt;/li&gt;
&lt;li&gt;Returning the generated mnemonic for wallet setup.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Create or Recover a Wallet
&lt;/h3&gt;

&lt;p&gt;Now, locate &lt;code&gt;// TODO: Implement method to create or recover a wallet&lt;/code&gt; and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;createOrRecoverWallet&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;recoveryMnemonic&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;mnemonic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recoveryMnemonic&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="n"&gt;_generateMnemonic&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// 2&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;directory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;getApplicationDocumentsDirectory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// 3&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;storagePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${directory.path}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;$LDK_NODE_DIR&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// 4&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEntropyBip39Mnemonic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;mnemonic:&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Mnemonic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mnemonic&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNetwork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;network&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setStorageDirPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;storagePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEsploraServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;esploraServerUrl:&lt;/span&gt; &lt;span class="n"&gt;WalletRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;esploraURL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// 5&lt;/span&gt;
    &lt;span class="n"&gt;ldkNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// 6&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// 7&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_secureStorage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;upsertWalletMnemonic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;mnemonic:&lt;/span&gt; &lt;span class="n"&gt;mnemonic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// 8&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mnemonic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this section, you are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deciding whether to create a new wallet or recover an existing one.&lt;/li&gt;
&lt;li&gt;Getting the application's document directory for data storage.&lt;/li&gt;
&lt;li&gt;Defining the storage path for the LDK node's data.&lt;/li&gt;
&lt;li&gt;Setting up the LDK node with the specified configuration using the builder.&lt;/li&gt;
&lt;li&gt;Building the LDK node based on the provided configuration.&lt;/li&gt;
&lt;li&gt;Starting the LDK node for network interaction.&lt;/li&gt;
&lt;li&gt;Securely storing the mnemonic for future use.&lt;/li&gt;
&lt;li&gt;Returning the mnemonic, which is essential for wallet management.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Retrieve Wallet Information
&lt;/h3&gt;

&lt;p&gt;Now, let's locate &lt;code&gt;// TODO: Implement method to retrieve wallet mnemonic from storage&lt;/code&gt; and replace it with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getWalletMnemonic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_secureStorage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getWalletMnemonic&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we're retrieving the wallet's mnemonic from secure storage and returning it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get Lightning Node ID
&lt;/h3&gt;

&lt;p&gt;Now, let's locate &lt;code&gt;// TODO: Implement method to retrieve Lightning node ID&lt;/code&gt; and replace it with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getNodeId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, you're retrieving your wallet LDK node's ID and returning it as a string.&lt;/p&gt;

&lt;p&gt;Now, in the &lt;code&gt;_getWalletInformation()&lt;/code&gt; method locate &lt;code&gt;// TODO: Retrieve our own node ID&lt;/code&gt; and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nodeId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;getNodeId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;Wallet&lt;/code&gt; object, replace &lt;code&gt;nodeId: 'dummy_node_id'&lt;/code&gt; with &lt;code&gt;nodeId: nodeId&lt;/code&gt;, &lt;code&gt;esploraUrl: 'dummy_esplora_url'&lt;/code&gt; with &lt;code&gt;esploraUrl: esploraURL&lt;/code&gt;, and &lt;code&gt;network: 'dummy_network'&lt;/code&gt; with &lt;code&gt;network: network.name&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's test the app! If it's already running, perform a hot reload and click the "&lt;em&gt;Create Wallet&lt;/em&gt;" button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yPkIAOut--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/YXWffmr/wallet-creation-to-home-ss-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yPkIAOut--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/YXWffmr/wallet-creation-to-home-ss-2.png" alt="Wallet Creation To Home Screen" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you'll be on the home screen. To view your mnemonic and node ID, click the popup menu button in the app's toolbar and select "&lt;em&gt;Wallet Info&lt;/em&gt;."&lt;/p&gt;

&lt;p&gt;The Wallet Information screen will appear, displaying your wallet information. Click on "&lt;em&gt;Display Mnemonic&lt;/em&gt;" and a dialog will pop up, revealing your wallet mnemonic as:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RlwqmB8z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/rkhSdL6/wallet-info-mnemonic-display-ss-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RlwqmB8z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/rkhSdL6/wallet-info-mnemonic-display-ss-3.png" alt="Wallet Information and Mnemonic Dialog" width="300" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next section, we'll focus on implementing Bitcoin on-chain functionality in our app.&lt;/p&gt;

&lt;h2&gt;
  
  
  On-Chain Functionality
&lt;/h2&gt;

&lt;p&gt;In this section we'll implement some essential functions for on-chain Bitcoin transactions. Let's dive into it:&lt;/p&gt;

&lt;h3&gt;
  
  
  Retrieve On-Chain Address
&lt;/h3&gt;

&lt;p&gt;To get your Bitcoin on-chain address, locate &lt;code&gt;// TODO: Implement method to retrieve on-chain address&lt;/code&gt; and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getOnChainAddress&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Address&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newOnchainAddress&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;getOnChainAddress&lt;/code&gt; method requests a new Bitcoin on-chain address from the LDK Node and returns it as a string. This address is crucial for receiving on-chain Bitcoin transactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retrieve On-Chain Balance
&lt;/h3&gt;

&lt;p&gt;Next, replace &lt;code&gt;// TODO: Implement method to retrieve on-chain balance&lt;/code&gt; with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getOnChainBalance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;syncWallets&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// 2&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;totalOnchainBalanceSats&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, we're performing the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Synchronizing the wallet to ensure up-to-date balance information.&lt;/li&gt;
&lt;li&gt;Retrieving and returning the total Bitcoin on-chain balance in sats. This balance represents the amount of Bitcoin you have in your on-chain wallet.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, In the &lt;code&gt;_getWalletInformation()&lt;/code&gt; method locate &lt;code&gt;// TODO: Retrieve on-chain balance and address information&lt;/code&gt; and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;onChainBalanceSats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;getOnChainBalance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;onChainAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;getOnChainAddress&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code retrieves both the on-chain balance and address, ensuring that your wallet's information is up to date.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Wallet&lt;/code&gt; object replace &lt;code&gt;onChainBalanceSats: 0&lt;/code&gt; with &lt;code&gt;onChainBalanceSats: onChainBalanceSats&lt;/code&gt; and &lt;code&gt;onChainAddress: 'dummy_address'&lt;/code&gt; with &lt;code&gt;onChainAddress: onChainAddress&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once you've made these updates, perform a hot reload of your app. Afterward, click the refresh icon on the home screen, situated in the row with the balance view.&lt;/p&gt;

&lt;p&gt;After the refresh is complete, you'll see your Bitcoin on-chain address displayed, replacing '&lt;em&gt;dummy_address&lt;/em&gt;'. The QR code will also be encoded with this Bitcoin on-chain address.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_Zt7ZTur--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/J7VKH4c/bitcoin-onchain-address-ss-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Zt7ZTur--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/J7VKH4c/bitcoin-onchain-address-ss-4.png" alt="Bitcoin On-Chain Address Display" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's proceed to send some testnet Bitcoin (tBTC) to that address. &lt;/p&gt;

&lt;p&gt;You can get some tBTC to play with from a testnet bitcoin faucet, which gives out free tBTC on demand. Here are a few testnet faucets to get you started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://coinfaucet.eu/en/btc-testnet/"&gt;https://coinfaucet.eu/en/btc-testnet/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bitcoinfaucet.uo1.net/"&gt;https://bitcoinfaucet.uo1.net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://testnet-faucet.com/btc-testnet/"&gt;https://testnet-faucet.com/btc-testnet/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kuttler.eu/en/bitcoin/btc/faucet/"&gt;https://kuttler.eu/en/bitcoin/btc/faucet/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PvHOF0An--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/4KRrytS/bitcoin-onchain-balance-received-ss-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PvHOF0An--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/4KRrytS/bitcoin-onchain-balance-received-ss-5.png" alt="Bitcoin On-Chain Balance Received" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So here with testnet bitcoin, we're not risking real funds. So it's good!&lt;/p&gt;

&lt;p&gt;Now, let's implement the functionality to send on-chain Bitcoin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Send On-Chain Bitcoin
&lt;/h3&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Implement method to send funds to an on-chain address&lt;/code&gt; and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sendToOnchainAddress&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;amountSats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;internal:&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// 2&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;txid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendToOnchainAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;address:&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;amountSats:&lt;/span&gt; &lt;span class="n"&gt;amountSats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'[WalletRepository] Send On-Chain Txid: &lt;/span&gt;&lt;span class="si"&gt;${txid.internal}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// 3&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;txid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, you're doing the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating an &lt;code&gt;Address&lt;/code&gt; object with the provided recipient's on-chain Bitcoin address.&lt;/li&gt;
&lt;li&gt;Initiating an on-chain transaction to send the specified amount of sats to the address.&lt;/li&gt;
&lt;li&gt;Returning the transaction ID (txid) for reference.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, perform a hot reload of your app, navigate to the &lt;strong&gt;Payments&lt;/strong&gt; tab on the home screen, click the floating action button, and choose '&lt;strong&gt;SEND TO BTC ADDRESS&lt;/strong&gt;' Enter the recipient's on-chain Bitcoin address and the amount in sats.&lt;/p&gt;

&lt;p&gt;Add testnet bitcoin on-chain address in their, if you don't have any bitcoin testnet address just do one thing, send me some tBTC here &lt;code&gt;tb1qyvp29ysl00rqrayyh633fgmdqsqsucwtnaw9n5&lt;/code&gt; 🙃. Also specify the amount that you want to send in sats. Click on submit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--petZPuA1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/fdYr9Nw/bitcoin-send-onchain-ss6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--petZPuA1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/fdYr9Nw/bitcoin-send-onchain-ss6.png" alt="Send On-Chain" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the payment is successful, you'll see a success indicator screen, and the transaction ID (txid) will be displayed on the console. You can copy this txid and paste it into a block explorer like &lt;a href="https://mempool.space/testnet"&gt;https://mempool.space/testnet&lt;/a&gt; to view your transaction details.&lt;/p&gt;

&lt;p&gt;One thing to note is that the current LDK Node Flutter plugin does not provide functionality for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieving Bitcoin on-chain transaction information. (Issue: &lt;a href="https://github.com/LtbLightning/ldk-node-flutter/issues/23"&gt;https://github.com/LtbLightning/ldk-node-flutter/issues/23&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Setting a custom fee rate in the sendToOnchainAddress method. (Issue: &lt;a href="https://github.com/LtbLightning/ldk-node-flutter/issues/24"&gt;https://github.com/LtbLightning/ldk-node-flutter/issues/24&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'll update this section once these issues are resolved. In the next section, we'll dive into setting up payment channels 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  Opening Payment Channel
&lt;/h2&gt;

&lt;p&gt;Let's kick things off by understanding what a payment channel is, but don't worry; we'll keep it simple. In simple terms, a payment channel is like a financial relationship between two Lightning nodes. It's established by funding a 2-of-2 multisignature address from the two channel partners.&lt;/p&gt;

&lt;p&gt;So, payment channels are built on top of 2-of-2 multisignature addresses.&lt;/p&gt;

&lt;p&gt;In summary, a multisignature address is where bitcoin is locked so that it requires multiple signatures to unlock and spend. In a 2-of-2 multisignature address, as used in the Lightning Network, there are two participating signers and both need to sign to spend the funds.&lt;/p&gt;

&lt;p&gt;To open a payment channel, we first need to establish a connection with another node. To do that, we require a "&lt;strong&gt;Node Identifier&lt;/strong&gt;" for that node. A Node Identifier typically looks like "&lt;strong&gt;NODEID@Address:Port&lt;/strong&gt;"&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;NODEID&lt;/strong&gt; is a unique identifier for a specific node, often presented in hexadecimal encoding.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Address:Port&lt;/strong&gt; is a network address identifier where the node can be reached. This can be in various formats, like TCP/IP (IPv4 or IPv6 address with a TCP port number) or TCP/Tor (a Tor "onion" address with a TCP port number).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, the &lt;strong&gt;Node Identifier&lt;/strong&gt; for the &lt;a href="https://mempool.space/testnet/lightning/node/03ba00a57cec1cef4873065ad54d0912696274cc53155b29a3b1256720e33a0943"&gt;PLEBNET.DEV testnet lightning node&lt;/a&gt; looks like this: &lt;code&gt;03ba00a57cec1cef4873065ad54d0912696274cc53155b29a3b1256720e33a0943@24.199.122.244:19735&lt;/code&gt;. You can often find the identifier encoded in a QR code for easy scanning and connecting.&lt;/p&gt;

&lt;p&gt;Keep in mind that to open a payment channel, you need the Node Identifier, which includes nodeId, address/host, and port. Also, you need to specify the channel amount, which is the total channel capacity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's a pro tip&lt;/strong&gt;: You can choose to push/send an amount to your channel partner during channel funding. This helps balance the channel right from the start and allows you to receive payments right away. &lt;strong&gt;But be careful when setting this value because it essentially sends money to your channel partner&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So before constructing the payment channel we must first be connected with our channel peer to which we want to open a payment channel with. The good news is, LDK offers a convenient method called &lt;code&gt;connectOpenChannel&lt;/code&gt; to connect to a node and open a new channel. It also handles disconnects and reconnections automatically.&lt;/p&gt;

&lt;p&gt;Let's get our hands dirty by implementing the method to open a Lightning payment channel. Find the &lt;code&gt;// TODO: Implement method to open a Lightning payment channel&lt;/code&gt; and replace it with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;openPaymentChannel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;amountSat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;pushToCounterpartySat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;connectOpenChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;netaddress:&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NetAddress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;iPv4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;addr:&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;port:&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;nodeId:&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PublicKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;internal:&lt;/span&gt; &lt;span class="n"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;channelAmountSats:&lt;/span&gt; &lt;span class="n"&gt;amountSat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;announceChannel:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;pushToCounterpartyMsat:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pushToCounterpartySat&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;satoshisToMilliSatoshis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pushToCounterpartySat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;openPaymentChannel&lt;/code&gt; method lets you establish a payment channel with a specific node, connect to it, and optionally announce the channel to the network. You can also specify an optional amount to push to your channel partner.&lt;/p&gt;

&lt;p&gt;But that's not all. We also need a way to list all the payment channels we've opened. Replace &lt;code&gt;// TODO: Implement method to list Lightning payment channels&lt;/code&gt; with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ChannelDetails&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;listPaymentChannels&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;channels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listChannels&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;listPaymentChannels&lt;/code&gt; method is used to retrieve and return a list of payment channels associated with your wallet.&lt;/p&gt;

&lt;p&gt;And, we're not done yet! To keep you in the loop, let's implement getting the list of connected peers. Replace &lt;code&gt;// TODO: Implement method to list Lightning peers&lt;/code&gt; with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PeerDetails&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;listPeers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;peers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listPeers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;peers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;listPeers&lt;/code&gt; method fetches and returns a list of peer details, representing the peers connected on the Lightning Network to our node.&lt;/p&gt;

&lt;p&gt;Finally, let's implement getting all the transaction information by replacing &lt;code&gt;// TODO: Implement method to list Lightning transactions&lt;/code&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PaymentDetails&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;listTransactions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;paymentDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PaymentDetails&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[];&lt;/span&gt;
    &lt;span class="c1"&gt;// 2&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;payments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listPayments&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// 3&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PaymentStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Succeeded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;paymentDetails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// 4&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;paymentDetails&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we're doing the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initializing a list to store payment details.&lt;/li&gt;
&lt;li&gt;Retrieving a list of all payments made through your wallet.&lt;/li&gt;
&lt;li&gt;Filtering and adding successful payments to the list of payment details.&lt;/li&gt;
&lt;li&gt;Returning the list of successful payment details.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, head over to the &lt;code&gt;_getWalletInformation()&lt;/code&gt; method and replace &lt;code&gt;// TODO: Retrieve lists of payment channels, peers, and payment details&lt;/code&gt; with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;    &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ChannelDetails&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;paymentChannelsList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;listPaymentChannels&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PeerDetails&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;peersList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;listPeers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PaymentDetails&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;paymentList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;listTransactions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, locate &lt;code&gt;// TODO: Initialize variables to hold various wallet information&lt;/code&gt; and replace it with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;inboundCapacitySats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;outboundCapacitySats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;bolt11Invoice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, locate &lt;code&gt;// TODO: Calculate inbound and outbound channel capacities&lt;/code&gt; and replace it with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;paymentChannelsList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;inboundCapacitySats&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt;
          &lt;span class="n"&gt;milliSatoshisToSatoshis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;inboundCapacityMsat&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;outboundCapacitySats&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt;
          &lt;span class="n"&gt;milliSatoshisToSatoshis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;outboundCapacityMsat&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;Wallet&lt;/code&gt; object, replace &lt;code&gt;inboundCapacitySats: 0&lt;/code&gt; with &lt;code&gt;inboundCapacitySats: inboundCapacitySats&lt;/code&gt;, &lt;code&gt;outboundCapacitySats: 0&lt;/code&gt; with &lt;code&gt;outboundCapacitySats: outboundCapacitySats&lt;/code&gt;, &lt;code&gt;paymentChannelsList: const []&lt;/code&gt; with &lt;code&gt;paymentChannelsList: paymentChannelsList&lt;/code&gt;, &lt;code&gt;peersList: const []&lt;/code&gt; with &lt;code&gt;peersList: peersList&lt;/code&gt; and &lt;code&gt;paymentsList: const []&lt;/code&gt; with &lt;code&gt;paymentsList: paymentList&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, perform a hot reload of your app and run it. Refresh the app by clicking the refresh icon on home screen. To open a payment channel, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the "&lt;strong&gt;Channels&lt;/strong&gt;" tab.&lt;/li&gt;
&lt;li&gt;Click on the floating action button and select "&lt;strong&gt;ENTER A NODE URI&lt;/strong&gt;" to open the &lt;code&gt;OpenChannelScreen&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enter the node ID, address, port, amount, and counterparty amount.&lt;/li&gt;
&lt;li&gt;Click "&lt;strong&gt;submit&lt;/strong&gt;."&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, we'll be opening a payment channel with the &lt;a href="https://mempool.space/testnet/lightning/node/03ba00a57cec1cef4873065ad54d0912696274cc53155b29a3b1256720e33a0943"&gt;PLEBNET.DEV testnet Lightning node&lt;/a&gt; using its node identifier: "&lt;code&gt;03ba00a57cec1cef4873065ad54d0912696274cc53155b29a3b1256720e33a0943@24.199.122.244:19735&lt;/code&gt;".&lt;/p&gt;

&lt;p&gt;If everything goes as planned, you'll see a success screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FUgzY9yO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/DbYBFzQ/opening-payment-channel-ss7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FUgzY9yO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/DbYBFzQ/opening-payment-channel-ss7.png" alt="Opening Payment Channel" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking "&lt;strong&gt;okay&lt;/strong&gt;" will take you back to the home screen, where you can see that you now have an open channel with 100,000 sats of capacity, 49,000 sats outbound capacity, and 49,000 sats inbound capacity. The rest is the Bitcoin on-chain fees for opening a payment channel by funding a 2-of-2 multisignature address, which is recorded on the Bitcoin blockchain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cm3R3VwT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/Fgj6SL3/channels-tab-ss-8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cm3R3VwT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/Fgj6SL3/channels-tab-ss-8.png" alt="Channels Tab" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's refresh the wallet, and you'll see the status of your channel. You may need to wait a bit for the funding transaction to be recorded on the Bitcoin blockchain, similar to waiting for confirmations when acquiring Bitcoin from a faucet.&lt;/p&gt;

&lt;p&gt;To check if our channel is ready for action, look at the icon next to the list tile, showing the number of confirmations needed for the channel to be usable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7iYn2sig--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/5vJSMTw/channel-ready-ss9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7iYn2sig--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/5vJSMTw/channel-ready-ss9.png" alt="Channel Ready" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you see a circle checkmark icon, that means your channel with the &lt;a href="https://mempool.space/testnet/lightning/node/03ba00a57cec1cef4873065ad54d0912696274cc53155b29a3b1256720e33a0943"&gt;PLEBNET.DEV testnet Lightning node&lt;/a&gt; is open, funded, and ready for action!&lt;/p&gt;

&lt;p&gt;Also, to take a look at your connected node peers. To do that, click on the pop-up menu button in the app bar, then click "Wallet Info" and select "List Channel Peers." This will display a dialog with all the connected peers to our node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NOs12RDK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/PzJLWTn/wallet-info-node-peer-dialog-ss-10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NOs12RDK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/PzJLWTn/wallet-info-node-peer-dialog-ss-10.png" alt="Wallet Info and Node Peers" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating BOLT11 Invoice
&lt;/h2&gt;

&lt;p&gt;Most payments on the Lightning Network start with an invoice, generated by the recipient of the payment.&lt;/p&gt;

&lt;p&gt;An invoice is a simple payment instruction containing information such as a unique payment identifier (payment hash), amount, and optional text description.&lt;/p&gt;

&lt;p&gt;The payment hash is the most important part of the invoice, allowing the payment to travel across multiple channels atomically.&lt;/p&gt;

&lt;p&gt;Invoices are typically communicated "out of band," using methods like QR codes, email, or text messages. It would be cool to integrate a peer-to-peer messaging feature using Nostr, but for now, let's stick to creating an invoice.&lt;/p&gt;

&lt;p&gt;Now, find &lt;code&gt;// TODO: Implement method to create a BOLT11 invoice&lt;/code&gt; and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;createInvoice&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;amountSat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;invoice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;receivePayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;amountMsat:&lt;/span&gt; &lt;span class="n"&gt;amountSat&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// 2&lt;/span&gt;
      &lt;span class="nl"&gt;description:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isNotEmpty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;
          &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Bijli Invoice'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// 3&lt;/span&gt;
      &lt;span class="nl"&gt;expirySecs:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// 4&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the breakdown of what this code does:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an invoice to receive a payment with the specified amount.&lt;/li&gt;
&lt;li&gt;Set the invoice description or use a default if not provided.&lt;/li&gt;
&lt;li&gt;Set the expiration time for the invoice (in seconds).&lt;/li&gt;
&lt;li&gt;Return the internal representation of the created invoice as a string.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;LDK also provides an option for creating a zero-sats invoice. This type of invoice is used when you want to request and receive a payment without specifying the amount; the sender determines the amount. To implement this, locate &lt;code&gt;// TODO: Implement method to create a zero-sat BOLT11 invoice&lt;/code&gt; and replace it with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;createZeroSatInvoice&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;invoice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;receiveVariableAmountPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;nodeId:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="c1"&gt;// 2&lt;/span&gt;
      &lt;span class="nl"&gt;description:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isNotEmpty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;
          &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Bijli Invoice'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// 3&lt;/span&gt;
      &lt;span class="nl"&gt;expirySecs:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// 4&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;invoice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;internal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Created a zero-sat invoice to receive a variable amount payment&lt;/li&gt;
&lt;li&gt;Set the invoice description or use a default if not provided.&lt;/li&gt;
&lt;li&gt;Set the expiration time for the invoice (in seconds).&lt;/li&gt;
&lt;li&gt;Return the internal representation of the created invoice as a string.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Moving on to the &lt;code&gt;_getWalletInformation()&lt;/code&gt; method, locate &lt;code&gt;// TODO: If there are inbound capacity, create a zero-satoshis invoice (BOLT11 format).&lt;/code&gt; and replace it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inboundCapacitySats&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;bolt11Invoice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;createZeroSatInvoice&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Just a quick note&lt;/strong&gt;: &lt;code&gt;inboundCapacitySats&lt;/code&gt; is the amount that you're allowed to receive on the Lightning Network. If you don't have any inbound capacity, you can't receive on Lightning. To balance inbound and outbound capacity, nodes should open channels to others and encourage others to open channels to their node.&lt;/p&gt;

&lt;p&gt;When we opened a payment channel in the &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iK4NM2ZL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/%23opening-payment-channel" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iK4NM2ZL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/%23opening-payment-channel" alt="Opening Payment Channel" width="" height=""&gt;&lt;/a&gt; section we opened the payment channel with capacity of 100,000 sats and we had also pushed 50,000 sats to our channel partner, which means we've inbound capacity of 50,000 sats and outbound capacity of 50,000 sats. Therefore we can receive upto 50,000 sats and can send upto 50,000 sats on lightning.&lt;/p&gt;

&lt;p&gt;Now, in the &lt;code&gt;Wallet&lt;/code&gt; object, replace &lt;code&gt;bolt11Invoice: 'dummy_invoice'&lt;/code&gt; with &lt;code&gt;bolt11Invoice: bolt11Invoice&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Give your app a hot reload and click on the refresh icon on the home screen. Then head to the "&lt;strong&gt;Receive&lt;/strong&gt;" tab and click on child the "&lt;strong&gt;LIGHTNING&lt;/strong&gt;" tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qzES4n_H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/0f9SGLs/creating-invoice-ss-11.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qzES4n_H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/0f9SGLs/creating-invoice-ss-11.png" alt="Zero-sat Invoice" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The invoice displayed there is a zero-sats invoice with a default description. If you want to customize this invoice, click on the "&lt;strong&gt;EDIT REQUEST&lt;/strong&gt;" button, and a dialog will pop up. Enter the description and the amount in sats.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S8JybQCH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/P48kYhZ/creating-invoice-ss-12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S8JybQCH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/P48kYhZ/creating-invoice-ss-12.png" alt="Creating Invoice" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, give it a go by paying this invoice with a different Lightning testnet wallet. You can download the &lt;a href="https://play.google.com/store/apps/details?id=fr.acinq.eclair.wallet"&gt;Eclair Mobile Testnet wallet&lt;/a&gt; from the Play Store, for example. In Eclair, grab some tBTC from a faucet, open a payment channel with the same &lt;a href="https://mempool.space/testnet/lightning/node/03ba00a57cec1cef4873065ad54d0912696274cc53155b29a3b1256720e33a0943"&gt;PLEBNET.DEV testnet Lightning node&lt;/a&gt;, and then try to pay this invoice from the Eclair wallet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8bMBylGL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/D1YRs57/eclair-paying-ss-13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8bMBylGL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/D1YRs57/eclair-paying-ss-13.png" alt="Paying from Eclair" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the payment goes through in Eclair, click on the refresh icon in "Bijli," and when the refreshing is complete, switch to the "&lt;strong&gt;Payments&lt;/strong&gt;" tab. You'll see a ListTile with payment information, which means you successfully received sats on Lightning! ⚡&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mut1drIn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/8Mcvndd/payments-tab-ss-14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mut1drIn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/8Mcvndd/payments-tab-ss-14.png" alt="Payments Tab" width="300" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where the Lightning Network shines, enabling quick and hassle-free payments without the need to wait for confirmations. Now, let's move on to learning how to pay a BOLT11 invoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paying an invoice
&lt;/h2&gt;

&lt;p&gt;In the previous section, we learned how to create an invoice and paid it from an external wallet. Now, it's time to pay an invoice from our wallet that was generated by the Eclair wallet.&lt;/p&gt;

&lt;p&gt;Locate &lt;code&gt;// TODO: Implement method to send an off-chain Lightning payment&lt;/code&gt; and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PaymentStatus&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sendOffChainPayment&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;bolt11Invoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;paymentHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;invoice:&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Bolt11Invoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;internal:&lt;/span&gt; &lt;span class="n"&gt;bolt11Invoice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// 2&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;paymentHash:&lt;/span&gt; &lt;span class="n"&gt;paymentHash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// 3&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;!.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what this code does:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It sends a Bitcoin Lightning payment using the specified BOLT11 invoice.&lt;/li&gt;
&lt;li&gt;It retrieves the payment details using the payment hash.&lt;/li&gt;
&lt;li&gt;It returns the status of the payment, indicating whether it was successful, pending, or failed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, perform a hot reload of your app. In the "&lt;strong&gt;Payments&lt;/strong&gt;" tab, click on the floating action button, then select "&lt;strong&gt;PASTE AN INVOICE&lt;/strong&gt;". This will open the &lt;code&gt;SendOffChainScreen&lt;/code&gt;. Paste the invoice generated by the Eclair wallet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A_J_zJf2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/PDcvmCy/paste-invoice-screen-ss-14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A_J_zJf2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/PDcvmCy/paste-invoice-screen-ss-14.png" alt="Paste Invoice Screen" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click "continue," and you'll see a dialog displaying the invoice details, including the requested amount and description.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zYH1VlEJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/DkQ6P0x/invoice-decode-dialog-ss-15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zYH1VlEJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/DkQ6P0x/invoice-decode-dialog-ss-15.png" alt="SendOffChain Dialog" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click "&lt;strong&gt;Approve&lt;/strong&gt;" in the dialog, and when the payment is successful, you'll see the "Success Indicator" screen.&lt;/p&gt;

&lt;p&gt;Click "&lt;strong&gt;okay&lt;/strong&gt;" on the success screen, and you'll return to the home screen. Check the transaction information in the "&lt;strong&gt;Payments&lt;/strong&gt;" tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GCtz0hQq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/Qm5RKzV/payments-tab-16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GCtz0hQq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/Qm5RKzV/payments-tab-16.png" alt="Payments Tab" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's how you pay an invoice and manage your Lightning wallet with ease. Enjoy the power of Lightning Network! ⚡&lt;/p&gt;

&lt;h2&gt;
  
  
  Payment Delivery
&lt;/h2&gt;

&lt;p&gt;To make a payment on the Lightning Network, the recipient must first create an invoice to receive the payment. This invoice encodes essential information, including a unique payment identifier (payment hash), the payment amount, and an optional text description.&lt;/p&gt;

&lt;p&gt;The payment hash within the invoice plays a crucial role by enabling the payment to be routed across multiple channels. This means that payments can be made even when there's no direct payment channel between the sender and the recipient.&lt;/p&gt;

&lt;p&gt;In our example, we don't have a direct payment channel with the Eclair Lightning wallet. However, we do share a payment channel with the PLEBNET.DEV Lightning node. The Eclair wallet also has a payment channel with the same PLEBNET.DEV Lightning node. Therefore, when we send or receive funds to and from the Eclair wallet, we're effectively routing our payment through the PLEBNET.DEV Lightning node.&lt;/p&gt;

&lt;p&gt;So far, we've covered sending and receiving on-chain transactions, opening payment channels, and sending and receiving funds on the Lightning Network. In the next section, we'll explore how to close a payment channel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing a payment channel
&lt;/h2&gt;

&lt;p&gt;In the Lightning Network, closing a payment channel may come with on-chain transaction fees. Therefore, it's generally advisable to keep channels open for as long as possible. Rebalancing the channel allows for continued use and an unlimited number of payments.&lt;/p&gt;

&lt;p&gt;However, there are situations where closing a channel is necessary. This can include reducing the balance for security reasons or when the channel partner becomes unresponsive.&lt;/p&gt;

&lt;p&gt;To implement channel closing in our wallet, locate &lt;code&gt;// TODO: Implement method to close a Lightning payment channel&lt;/code&gt; and replace it with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;closePaymentChannel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ChannelId&lt;/span&gt; &lt;span class="n"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="n"&gt;ldk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PublicKey&lt;/span&gt; &lt;span class="n"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ldkNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;closeChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;channelId:&lt;/span&gt; &lt;span class="n"&gt;channelId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;counterpartyNodeId:&lt;/span&gt; &lt;span class="n"&gt;nodeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;closePaymentChannel&lt;/code&gt; method is used to close a payment channel with the specified channel ID and counterparty node ID.&lt;/p&gt;

&lt;p&gt;Now, just perform a hot reload of the app. Go to the "&lt;strong&gt;Channels&lt;/strong&gt;" tab, and click on "&lt;strong&gt;CLOSE&lt;/strong&gt;" on the channel's ListTile. A dialog will pop up for confirmation. Click "&lt;strong&gt;YES&lt;/strong&gt;" there, and when the channel is closed, you'll see the success screen displaying the channel ID that was closed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8DoR-swV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/FbLFScR/closing-channel-ss-17.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8DoR-swV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/FbLFScR/closing-channel-ss-17.png" alt="Closing Channel" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Closing a payment channel can be a necessary step in managing your Lightning Network wallet and ensuring the security and flexibility of your funds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node and Channel Backups
&lt;/h2&gt;

&lt;p&gt;As we continue our journey, it's important to note that we don't currently have a channel backup mechanism in place. All the data related to node and channel states are stored locally in the &lt;code&gt;storagePath&lt;/code&gt; as defined in the &lt;code&gt;createOrRecoverWallet&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;This is actually a very important consideration when running a Lightning node, is the issue of backups. Unlike a Bitcoin wallet, where a BIP-39 mnemonic phrase and BIP-32 can recover the entire state of the wallet. However, in Lightning, things are a bit more complex.&lt;/p&gt;

&lt;p&gt;Lightning wallets do use a BIP-39 mnemonic phrase for on-chain wallet backup, but this phrase alone is not sufficient to restore a Lightning node. Channels, which are a fundamental part of the Lightning Network, are constructed in a way that the mnemonic phrase can't fully restore a Lightning node.&lt;/p&gt;

&lt;p&gt;And also, when it comes to channel state backups, there's no standardized approach that every Lightning wallet follows. Some wallets store channel states on Google Drive, some on their own remote servers, and others store them locally on the user's device. Each of these practices carries the risk of data loss and data inconsistency risks.&lt;/p&gt;

&lt;p&gt;So there is no consistent backup mechanism across different Lightning node and wallet implementations. Hence, you should not store large amounts in a Lightning wallet.  Large amounts should be kept in a cold wallet that is not online and can only transact on-chain.&lt;/p&gt;

&lt;p&gt;It's crucial to keep this in mind to ensure the safety and security of your funds when operating on the Lightning Network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Incoming Channel Opening Requests Struggle
&lt;/h2&gt;

&lt;p&gt;During the development of this project, I encountered a significant challenge related to incoming channel opening requests. I initially struggled while attempting to build the node in the &lt;code&gt;createOrRecoverWallet&lt;/code&gt; method, particularly when using the &lt;code&gt;.setListeningAddress&lt;/code&gt; method on &lt;code&gt;ldk.Builder()&lt;/code&gt;. To enable incoming channel opening requests, it's essential to set the listening address by specifying the IP address and listening port for the node, allowing it to listen for incoming channel requests.&lt;/p&gt;

&lt;p&gt;However, after extensive efforts and seeking guidance in the LDK Discord channel, I learned that running a node configured to listen for incoming connections is not a viable approach for mobile phones.&lt;/p&gt;

&lt;p&gt;Setting the IP address to the mobile device's IPv4 public address, which essentially corresponds to the ISP's address, presents challenges. This IP address is not stable, and many mobile providers place end devices behind NAT (Network Address Translation), further complicating the situation.&lt;/p&gt;

&lt;p&gt;In the words of @tnull, "if you don't want to go out of your way to implement hole punching or similar, I'd generally recommend disabling the listening port on mobile devices and relying on outbound connections only."&lt;/p&gt;

&lt;p&gt;You can find the complete communication on this topic here(&lt;a href="https://discord.com/channels/915026692102316113/978829624635195422/1155768160197279744"&gt;https://discord.com/channels/915026692102316113/978829624635195422/1155768160197279744&lt;/a&gt;), where @tnull provided a detailed explanation of this issue.&lt;/p&gt;

&lt;p&gt;Also, benthecarman suggested that the "best approach is probably just not calling setListeningAddress." This is the approach I followed in the &lt;code&gt;createOrRecoverWallet&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;For these reasons, we cannot have incoming channel opening requests on mobile devices. It's crucial to be aware of these limitations and work within the constraints of the mobile environment when developing Lightning Network applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As we wrap up this journey into the fascinating world of the Lightning Network, I want to express my deep thanks to the amazing team working on the LDK node project and all the dedicated developers who have contributed to the development of BDK and LDK. Your hard work not only opens new doors but also supports developers like me who are diving into the potential of this incredible technology.&lt;/p&gt;

&lt;p&gt;The Lightning Network isn't just a technological advance; it's a game-changer that promises faster, cheaper, and more efficient Bitcoin transactions. It unlocks countless possibilities, from tiny payments to decentralized finance and beyond.&lt;/p&gt;

&lt;p&gt;But remember, this is just the start. The Lightning Network is a vast and exciting world with endless opportunities. I encourage all readers to keep learning and explore further. Embrace this technology, experiment with it, and let your imagination run wild. The Lightning Network is a wave of innovation, and you have the chance to ride it.&lt;/p&gt;

&lt;p&gt;If you have questions or want to connect and share your experiences, feel free to reach out to me on &lt;a href="https://twitter.com/Anipy1"&gt;Twitter&lt;/a&gt;, &lt;a href="https://snort.social/p/npub1clqc0wnk2vk42u35jzhc3emd64c0u4g6y3su4x44g26s8waj2pzskyrp9x"&gt;Nostr&lt;/a&gt;, or &lt;a href="https://www.linkedin.com/in/aniketambore/"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thank you for joining me on this journey. ⚡🌊&lt;/p&gt;

</description>
      <category>bitcoin</category>
      <category>lightning</category>
      <category>flutter</category>
      <category>ldk</category>
    </item>
  </channel>
</rss>
