A Comprehensive Guide to Build a Stellar dApp from Scratch

A Comprehensive Guide to Build a Stellar dApp from Scratch

calenderSeptember 21, 2023 | Editor Choice
clock 4 min read
--:--
--:--
 Zaryab Rafique

Zaryab Rafique

Stellar is a layer 1 blockchain that uses the Stellar Consensus Protocol (SCP) to reach a consensus. It provides a platform for the developers to build projects, issue assets, and build anchors. You can also use the Stellar platform to create decentralized applications.

In this article, we will cover from scratch how to build the dApp on the Stellar Blockchain. We also see how to work with the smart contract development platform, deployment, testing, and web3 integration, and Freighter wallet with web frontend using the soroban cli typescript binding.

Soroban

Soroban is a Rust-based smart contract platform that helps developers write, deploy, and test smart contracts in Rust language. The platform is built to scale dApp with a developer-friendly environment, and is also fast in performance. Presently, Soroban exists as a preliminary release containing initial iterations of the smart contracts environment, a Rust SDK, a command-line interface (CLI), and an RPC server. 

Developers can author and experiment with contracts on their personal computers or deploy them to a designated trial network known as Futurenet. In this article, I will explain to you how to work with Soroban to write, deploy, and test smart contracts in the Rust language.

Install Rust & Soroban

Let's start by installing the Rust toolchain and Soroban CLI. If you are using Ubuntu/Linux, MAC OS, or Unix-like OS, open the terminal.

Install Rust

Install rustup by following the command:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Add Target

Add the wasm32-unknown-unknown target

rustup target add wasm32-unknown-unknown

Install the Soroban CLI

Soroban CLI can run Soroban contracts within a local sandbox, simulating the contract's execution environment on the network.

Install the Soroban CLI using cargo install.

cargo install --locked --version 0.9.4 soroban-cli

Create New Project

To create a new rust lib project use the following command in the terminal:

cargo new dapp-project --lib

Add Dependencies

After creating a project, open the Cargo.toml file that will look like this.

[package]
name = "dapp-project"
version = "0.1.0"
edition = "2021"
[dependencies]

 

Add the soroban dependencies in it.

[package]
name = "dapp-project"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[features]
testutils = ["soroban-sdk/testutils"]

[dependencies]
soroban-sdk = "0.9.2"

[dev_dependencies]
soroban-sdk = { version = "0.9.2", features = ["testutils"] }

[profile.release]
opt-level = "z"
overflow-checks = true
debug = 0
strip = "symbols"
debug-assertions = false
panic = "abort"
codegen-units = 1
lto = true

[profile.release-with-logs]
inherits = "release"
debug-assertions = true

Write Smart Contract

We will write a simple contract that sets string value to the ledger and get that value from the ledger.

Open the src/lib.rs file and write the following code in it.

#![no_std]
use soroban_sdk::{contract, contractimpl, symbol_short, Env, String, Symbol};

const KEY: Symbol = symbol_short!("KEY");

#[contract]
pub struct DAppContract;

#[contractimpl]
impl DAppContract {
  pub fn set_value(env: Env, value: String) {
    env.storage().instance().set(&KEY, &value);
  }

  pub fn get_value(env: Env) -> String {
    let value = env.storage().instance().get(&KEY).unwrap();

    value
  }
}

#[cfg(test)]
mod test {
use super::{DAppContract, DAppContractClient};
use soroban_sdk::{Env, String};
  #[test]
  fn test() {
    let env = Env::default();
    let contract_id = env.register_contract(None, DAppContract);
    let client = DAppContractClient::new(&env, &contract_id);
    let value = String::from_slice(&env, "InvoBlox");

    client.set_value(&value);

    assert_eq!(value, client.get_value());
 }
}

Build & Test Contract

To build the contract, you must run the following in the project root directory at the terminal.

cargo build --target wasm32-unknown-unknown --release

This command with --target wasm32-unknown-unknown and --release flags build and generate the .wasm file for deployment.

To test the project run the following command in the project root directory.

cargo test

 

Deploy Smart Contract on Futurenet

To deploy, first, you have to create the account that gives the Public and Private Key, then add funds to the account. Go to the Stellar Laboratory, create the account, fund with the friendbot tool, and make sure you are on the Futurenet.

After creating and funding the account, you have to run the following deployment script which deploys the contract to Stellar’s Futurenet. Must have the test lumens for deployment.

soroban contract deploy \

    --wasm target/wasm32-unknown-unknown/release/dapp_project.wasm \

    --source SAJKW3SKB4NDC67OI7ZNARNXBKCGJCEVFSIYRM3DYJ4ARACVDZPGYZDQ \

    --rpc-url https://rpc-futurenet.stellar.org:443 \

    --network-passphrase 'Test SDF Future Network ; October 2022'


The smart contract is deployed on the Stellar futurenet and we have the Contract ID for web3 integration.

Contract ID: CBM4ZILUTQL4UYXPGAOH53QNAYDH4CRQMDNZ5NZZNPNI27BSSU6BMP6S

Web3 Integration

Now, we have to do the web3 integration of smart contracts deployed with React JS App using the typescript binding and after importing the binding in App. After that, will do the Freighter Wallet integration to interact with the dApp. 

Generate Typescript Binding

To generate the typescript binding, we use the Contract ID deployed earlier and the build wasm file to create the web3 functions based on the smart contract functions.

Replace the Contract Name, Contract ID, WASM file path, and output directory in the following command. Once done, run this command at the terminal to the root of your project:

soroban contract bindings typescript --wasm target/wasm32-unknown-unknown/release/dapp_project.wasm \

 --output-dir /Users/muhammadzaryabrafique/Downloads/Invozone-Data/Zaryab/Blogs/Blog-7/dapp-project/ \

 --contract-name DAppBinding \

 --contract-id CBM4ZILUTQL4UYXPGAOH53QNAYDH4CRQMDNZ5NZZNPNI27BSSU6BMP6S

This command will generate the Typescript binding with the name of DAppBinding that stores at the path you give in the output-dir.

Create a React App

Next, we have to create the React JS App and configure this binding to the App. Let's create the App with the following command, make sure you have Node Js installed on your machine.

npx create-react-app stellar-dapp --template typescript

It will create the React app with a typescript template.

Configure the Bindings to the React App

First, you have to open the React App, copy the binding, and paste it into the root of your project. Then, add the binding to the package.json file in the dependencies section. 

"DAppBinding": "./DAppBinding",

Run the following command to add the binding to node_modules:

npm install

After that you can use the binding in your project.  Now import binding in the App.js file 

import DAppBinding from 'DAppBinding';

Here is the App.js file code with the get string function that uses the DAppBiinding. 

import React, { useState } from "react";
import "./App.css";
import DAppBinding from "DAppBinding";

function App() {
  const [value, Setvalue] = useState("");

  async function getValue() {
    let result = await DAppBinding.getValue();

    Setvalue(result);
  }

  return (
    <div className="App">
      <h2>Value: {value}</h2>
      <button onClick={getValue}>Get Value</button>
    </div>
  );
}

export default App;

Freighter Wallet integration

A Wallet is needed to interact with the Stellar dApp, We have the Freighter Wallet for interaction with dApp. Let's integrate the Freighter Wallet into our stellar-dapp. 

Add the following package to the package.json file in the dependencies section:

"stellar-wallets-kit": "github:Creit-Tech/Stellar-Wallets-Kit",

Run the following command to add the package to node_modules:

npm install

After installation, we can use the Stellar Wallet Kit in the project. Now do the wallet integration into the project.

import { StellarWalletsKit, WalletNetwork, WalletType, ISupportedWallet } from "stellar-wallets-kit";

export const FUTURENET_DETAILS = {
  network: "FUTURENET",
  networkUrl: "https://horizon-futurenet.stellar.org",
  networkPassphrase: "Test SDF Future Network ; October 2022",
};

function App(): JSX.Element {
  // Default to Futurenet network, only supported network for now
  const [selectedNetwork] = React.useState(FUTURENET_DETAILS);

  // Initial state, empty states for token/transaction details
  const [activePubKey, setActivePubKey] = React.useState("");
  // const [error, setError] = React.useState(null as string | null);

  // Setup swc, the user will set the desired wallet on connect
  const [SWKKit] = React.useState(
    new StellarWalletsKit({
      network: selectedNetwork.networkPassphrase as WalletNetwork,
      selectedWallet: WalletType.FREIGHTER,
    })
  );

  React.useEffect(() => {
    SWKKit.setNetwork(selectedNetwork.networkPassphrase as WalletNetwork);
  }, [selectedNetwork.networkPassphrase, SWKKit]);

  const connect = () => {
    // See https://github.com/Creit-Tech/Stellar-Wallets-Kit/tree/main for more options
    SWKKit.openModal({
      allowedWallets: [WalletType.ALBEDO, WalletType.FREIGHTER, WalletType.XBULL],
      
      onWalletSelected: async (option: ISupportedWallet) => {
         try {
          // Set selected wallet,  network, and public key
          SWKKit.setWallet(option.type);
          const publicKey = await SWKKit.getPublicKey();

          setActivePubKey(publicKey);

          console.log("publicKey", publicKey);

          SWKKit.setNetwork(WalletNetwork.FUTURENET);
        } catch (error) {
          console.log(error);
        }
      },
    });
  };

  useEffect(() => {
    connect();
  });
 

We have added the integrated stellar wallet kit to the project. Now we can connect the Freighter wallet and interact with dApp.

Conclusion

We have gone through a comprehensive guide to building a Stellar dApp from scratch. As we discussed the Soroban SDK for smart contract development, we set up the environment, created a new smart contract project, wrote the simple contract, then built it and deployed it on Futurenet. 

After we generated the contract typescript binding of the deployed contract. In the last, we created the React Ts App, added the binding to it, and did the Freighter Wallet integration. This is the complete flow, we have covered how to build a dApp from smart contract creation, dApp deployment, and testing to typescript binding and wallet integration.

 

Stellar is a layer 1 blockchain that uses the Stellar Consensus Protocol (SCP) to reach a consensus. It provides a platform for the developers to build projects, issue assets, and build anchors. You can also use the Stellar platform to create decentralized applications.

In this article, we will cover from scratch how to build the dApp on the Stellar Blockchain. We also see how to work with the smart contract development platform, deployment, testing, and web3 integration, and Freighter wallet with web frontend using the soroban cli typescript binding.

Soroban

Soroban is a Rust-based smart contract platform that helps developers write, deploy, and test smart contracts in Rust language. The platform is built to scale dApp with a developer-friendly environment, and is also fast in performance. Presently, Soroban exists as a preliminary release containing initial iterations of the smart contracts environment, a Rust SDK, a command-line interface (CLI), and an RPC server. 

Developers can author and experiment with contracts on their personal computers or deploy them to a designated trial network known as Futurenet. In this article, I will explain to you how to work with Soroban to write, deploy, and test smart contracts in the Rust language.

Install Rust & Soroban

Let's start by installing the Rust toolchain and Soroban CLI. If you are using Ubuntu/Linux, MAC OS, or Unix-like OS, open the terminal.

Install Rust

Install rustup by following the command:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Add Target

Add the wasm32-unknown-unknown target

rustup target add wasm32-unknown-unknown

Install the Soroban CLI

Soroban CLI can run Soroban contracts within a local sandbox, simulating the contract's execution environment on the network.

Install the Soroban CLI using cargo install.

cargo install --locked --version 0.9.4 soroban-cli

Create New Project

To create a new rust lib project use the following command in the terminal:

cargo new dapp-project --lib

Add Dependencies

After creating a project, open the Cargo.toml file that will look like this.

[package]
name = "dapp-project"
version = "0.1.0"
edition = "2021"
[dependencies]

 

Add the soroban dependencies in it.

[package]
name = "dapp-project"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[features]
testutils = ["soroban-sdk/testutils"]

[dependencies]
soroban-sdk = "0.9.2"

[dev_dependencies]
soroban-sdk = { version = "0.9.2", features = ["testutils"] }

[profile.release]
opt-level = "z"
overflow-checks = true
debug = 0
strip = "symbols"
debug-assertions = false
panic = "abort"
codegen-units = 1
lto = true

[profile.release-with-logs]
inherits = "release"
debug-assertions = true

Write Smart Contract

We will write a simple contract that sets string value to the ledger and get that value from the ledger.

Open the src/lib.rs file and write the following code in it.

#![no_std]
use soroban_sdk::{contract, contractimpl, symbol_short, Env, String, Symbol};

const KEY: Symbol = symbol_short!("KEY");

#[contract]
pub struct DAppContract;

#[contractimpl]
impl DAppContract {
  pub fn set_value(env: Env, value: String) {
    env.storage().instance().set(&KEY, &value);
  }

  pub fn get_value(env: Env) -> String {
    let value = env.storage().instance().get(&KEY).unwrap();

    value
  }
}

#[cfg(test)]
mod test {
use super::{DAppContract, DAppContractClient};
use soroban_sdk::{Env, String};
  #[test]
  fn test() {
    let env = Env::default();
    let contract_id = env.register_contract(None, DAppContract);
    let client = DAppContractClient::new(&env, &contract_id);
    let value = String::from_slice(&env, "InvoBlox");

    client.set_value(&value);

    assert_eq!(value, client.get_value());
 }
}

Build & Test Contract

To build the contract, you must run the following in the project root directory at the terminal.

cargo build --target wasm32-unknown-unknown --release

This command with --target wasm32-unknown-unknown and --release flags build and generate the .wasm file for deployment.

To test the project run the following command in the project root directory.

cargo test

 

Deploy Smart Contract on Futurenet

To deploy, first, you have to create the account that gives the Public and Private Key, then add funds to the account. Go to the Stellar Laboratory, create the account, fund with the friendbot tool, and make sure you are on the Futurenet.

After creating and funding the account, you have to run the following deployment script which deploys the contract to Stellar’s Futurenet. Must have the test lumens for deployment.

soroban contract deploy \

    --wasm target/wasm32-unknown-unknown/release/dapp_project.wasm \

    --source SAJKW3SKB4NDC67OI7ZNARNXBKCGJCEVFSIYRM3DYJ4ARACVDZPGYZDQ \

    --rpc-url https://rpc-futurenet.stellar.org:443 \

    --network-passphrase 'Test SDF Future Network ; October 2022'


The smart contract is deployed on the Stellar futurenet and we have the Contract ID for web3 integration.

Contract ID: CBM4ZILUTQL4UYXPGAOH53QNAYDH4CRQMDNZ5NZZNPNI27BSSU6BMP6S

Web3 Integration

Now, we have to do the web3 integration of smart contracts deployed with React JS App using the typescript binding and after importing the binding in App. After that, will do the Freighter Wallet integration to interact with the dApp. 

Generate Typescript Binding

To generate the typescript binding, we use the Contract ID deployed earlier and the build wasm file to create the web3 functions based on the smart contract functions.

Replace the Contract Name, Contract ID, WASM file path, and output directory in the following command. Once done, run this command at the terminal to the root of your project:

soroban contract bindings typescript --wasm target/wasm32-unknown-unknown/release/dapp_project.wasm \

 --output-dir /Users/muhammadzaryabrafique/Downloads/Invozone-Data/Zaryab/Blogs/Blog-7/dapp-project/ \

 --contract-name DAppBinding \

 --contract-id CBM4ZILUTQL4UYXPGAOH53QNAYDH4CRQMDNZ5NZZNPNI27BSSU6BMP6S

This command will generate the Typescript binding with the name of DAppBinding that stores at the path you give in the output-dir.

Create a React App

Next, we have to create the React JS App and configure this binding to the App. Let's create the App with the following command, make sure you have Node Js installed on your machine.

npx create-react-app stellar-dapp --template typescript

It will create the React app with a typescript template.

Configure the Bindings to the React App

First, you have to open the React App, copy the binding, and paste it into the root of your project. Then, add the binding to the package.json file in the dependencies section. 

"DAppBinding": "./DAppBinding",

Run the following command to add the binding to node_modules:

npm install

After that you can use the binding in your project.  Now import binding in the App.js file 

import DAppBinding from 'DAppBinding';

Here is the App.js file code with the get string function that uses the DAppBiinding. 

import React, { useState } from "react";
import "./App.css";
import DAppBinding from "DAppBinding";

function App() {
  const [value, Setvalue] = useState("");

  async function getValue() {
    let result = await DAppBinding.getValue();

    Setvalue(result);
  }

  return (
    <div className="App">
      <h2>Value: {value}</h2>
      <button onClick={getValue}>Get Value</button>
    </div>
  );
}

export default App;

Freighter Wallet integration

A Wallet is needed to interact with the Stellar dApp, We have the Freighter Wallet for interaction with dApp. Let's integrate the Freighter Wallet into our stellar-dapp. 

Add the following package to the package.json file in the dependencies section:

"stellar-wallets-kit": "github:Creit-Tech/Stellar-Wallets-Kit",

Run the following command to add the package to node_modules:

npm install

After installation, we can use the Stellar Wallet Kit in the project. Now do the wallet integration into the project.

import { StellarWalletsKit, WalletNetwork, WalletType, ISupportedWallet } from "stellar-wallets-kit";

export const FUTURENET_DETAILS = {
  network: "FUTURENET",
  networkUrl: "https://horizon-futurenet.stellar.org",
  networkPassphrase: "Test SDF Future Network ; October 2022",
};

function App(): JSX.Element {
  // Default to Futurenet network, only supported network for now
  const [selectedNetwork] = React.useState(FUTURENET_DETAILS);

  // Initial state, empty states for token/transaction details
  const [activePubKey, setActivePubKey] = React.useState("");
  // const [error, setError] = React.useState(null as string | null);

  // Setup swc, the user will set the desired wallet on connect
  const [SWKKit] = React.useState(
    new StellarWalletsKit({
      network: selectedNetwork.networkPassphrase as WalletNetwork,
      selectedWallet: WalletType.FREIGHTER,
    })
  );

  React.useEffect(() => {
    SWKKit.setNetwork(selectedNetwork.networkPassphrase as WalletNetwork);
  }, [selectedNetwork.networkPassphrase, SWKKit]);

  const connect = () => {
    // See https://github.com/Creit-Tech/Stellar-Wallets-Kit/tree/main for more options
    SWKKit.openModal({
      allowedWallets: [WalletType.ALBEDO, WalletType.FREIGHTER, WalletType.XBULL],
      
      onWalletSelected: async (option: ISupportedWallet) => {
         try {
          // Set selected wallet,  network, and public key
          SWKKit.setWallet(option.type);
          const publicKey = await SWKKit.getPublicKey();

          setActivePubKey(publicKey);

          console.log("publicKey", publicKey);

          SWKKit.setNetwork(WalletNetwork.FUTURENET);
        } catch (error) {
          console.log(error);
        }
      },
    });
  };

  useEffect(() => {
    connect();
  });
 

We have added the integrated stellar wallet kit to the project. Now we can connect the Freighter wallet and interact with dApp.

Conclusion

We have gone through a comprehensive guide to building a Stellar dApp from scratch. As we discussed the Soroban SDK for smart contract development, we set up the environment, created a new smart contract project, wrote the simple contract, then built it and deployed it on Futurenet. 

After we generated the contract typescript binding of the deployed contract. In the last, we created the React Ts App, added the binding to it, and did the Freighter Wallet integration. This is the complete flow, we have covered how to build a dApp from smart contract creation, dApp deployment, and testing to typescript binding and wallet integration.

 

FAQS

Stellar blockchain cleverly secure transactions by featuring each account with a public key alongside a private seed phrase, coupled with publish cryptography. Likewise, users must load funds in the Stellar blockchain anchor, a trusted entity to hold your deposits. 

The Stellar is a great choice with its faster, greener, and cheaper network as compared to other ones. Thanks to its Proof-of-Authority consensus mechanism, the core design makes it easy to create and launch digital assets, enabling ultra fast payments and reasonable prices. 

Developing solutions on the Stellar network necessitates expertise in blockchain fundamentals, proficiency in programming languages, familiarity with Stellar's SDKs and APIs, security awareness, and the ability to tailor solutions to specific use cases.

Ready to make something amazing?

ready to make banner

Ready to make something amazing?

mobile banner

Related Posts