diff --git a/docs/build/guides/dapps/frontend-guide.mdx b/docs/build/guides/dapps/frontend-guide.mdx new file mode 100644 index 000000000..7a4cf8045 --- /dev/null +++ b/docs/build/guides/dapps/frontend-guide.mdx @@ -0,0 +1,823 @@ +--- +title: Comprehensive frontend guide for Stellar dapps +description: Learn how to build functional frontend interfaces for Stellar dapps using React, Tailwind CSS, and the Stellar SDK. +--- + +## Pre-requisites: + +- Basic knowledge of React, Tailwind CSS, and related web technologies +- Basic understanding of the Stellar blockchain +- Node.js and npm installed +- Web browser with [Freighter Wallet](https://www.freighter.app) extension installed + +## 1. Introduction + +### The role of frontend in Stellar dapps + +Frontend development plays a crucial role in decentralized applications (dapps) built on the Stellar network. It serves as the primary interface between users and the underlying blockchain technology. A well-designed frontend not only makes your dapp accessible and user-friendly but also helps users interact seamlessly with complex blockchain operations. + +In Stellar dapps, the frontend is responsible for: + +1. Presenting blockchain data in a human-readable format +2. Facilitating user interactions with smart contracts and Stellar operations +3. Managing user accounts and keys securely +4. Providing real-time updates on transaction status and account balances +5. Guiding users through complex processes like multi-signature transactions or claimable balance operations + +### Importance of user interface and user experience + +The importance of a good user interface (UI) and user experience (UX) in Stellar dapps cannot be overstated. Blockchain technology can be intimidating for many users, and a well-designed UI/UX can make the difference between a successful dapp and one that users find frustrating or confusing. + +Key aspects of UI/UX in Stellar dapps include: + +1. Simplicity: Presenting complex blockchain concepts in an easy-to-understand manner +2. Transparency: Providing clear information about transaction fees, network status, and operation outcomes +3. Feedback: Offering immediate and clear feedback on user actions and transaction progress +4. Error Handling: Gracefully managing and explaining errors in a user-friendly way +5. Performance: Ensuring quick load times and responsive interactions, even when dealing with blockchain operations + +By focusing on these aspects, you can create Stellar dapps that are not only functional but also enjoyable to use, encouraging wider adoption of your application and the Stellar network as a whole. + +## 2. Setting up the development environment + +Before we start building our Stellar dapp, we need to set up our development environment. We'll be using React with Next.js for our frontend framework, Tailwind CSS for styling, and the Stellar SDK for interacting with the Stellar network. + +### Installing Node.js and npm + +First, make sure you have Node.js and npm (Node Package Manager) installed on your system. You can download and install them from the official Node.js website: https://nodejs.org/ + +To verify your installation, open a terminal and run: + +```bash +node --version +npm --version +``` + +Both commands should return version numbers if the installation was successful. + +### Setting up a Next.js project + +Next.js is a React framework that provides features such as server-side rendering and routing out of the box. To create a new Next.js project, run the following commands in your terminal: + +```bash +npx create-next-app@latest stellar-dapp +cd stellar-dapp +``` + +When prompted, choose the following options: + +- Would you like to use TypeScript? Yes +- Would you like to use ESLint? Yes +- Would you like to use Tailwind CSS? Yes +- Would you like to use `src/` directory? No +- Would you like to use App Router? Yes +- Would you like to customize the default import alias? No + +### Setup HTTPS on Localhost + +Freighter wallet requires a secure connection (HTTPS) to interact with your dapp. To enable HTTPS on localhost, you can use a tool like `mkcert`. Fortunately, Next.js provides built-in support for HTTPS. + +To enable HTTPS in your Next.js project, open the `package.json` file and edit the `scripts` section as follows: + +```json +"scripts": { + "dev": "next dev --experimental-https", +} +``` + +### Installing Stellar SDK and other dependencies + +To interact with the Stellar network, we'll need to install the Stellar SDK and some additional dependencies: + +```bash +npm install stellar-sdk @stellar/freighter-api bignumber.js +``` + +- `stellar-sdk`: The official Stellar SDK for interacting with the Stellar network +- `@stellar/freighter-api`: A library for integrating with the Freighter wallet (a popular Stellar wallet browser extension) +- `bignumber.js`: A library for arbitrary-precision decimal and non-decimal arithmetic + +Now that we have our development environment set up, we're ready to start building our Stellar dapp! + +## 3. Building basic interface elements + +In this section, we'll create reusable components for our Stellar dapp and implement forms and inputs using React and Tailwind CSS. + +### Creating reusable components + +Let's start by creating a button component that we'll use throughout our application. Create a new file `components/Button.tsx`: + +```typescript +import React from 'react'; + +interface ButtonProps { + onClick: () => void; + children: React.ReactNode; + disabled?: boolean; + className?: string; +} + +const Button: React.FC = ({ onClick, children, disabled = false, className = '' }) => { + return ( + + ); +}; + +export default Button; +``` + +This button component uses Tailwind CSS classes for styling and accepts props for customization. + +Next, let's create another helper button to help connect the Freighter wallet. Create a new file `components/ConnectWalletButton.tsx`: + +```typescript +"use client"; +import React from 'react' +import { setAllowed } from '@stellar/freighter-api' + +export interface ConnectButtonProps { + label: string + isHigher?: boolean +} + +export function ConnectButton({ label }: ConnectButtonProps) { + return ( + + ) +} +``` + +This button component uses the `setAllowed` function from the `@stellar/freighter-api` library to connect the Freighter wallet when clicked. + +### Implementing forms and inputs + +Next, let's create a reusable input component. Create a new file `components/Input.tsx`: + +```typescript +import React from 'react'; + +interface InputProps { + type: string; + placeholder: string; + value: string; + onChange: (e: React.ChangeEvent) => void; + className?: string; +} + +const Input: React.FC = ({ type, placeholder, value, onChange, className = '' }) => { + return ( + + ); +}; + +export default Input; +``` + +Now, let's create a form component that uses these reusable components. Create a new file `components/SendPaymentForm.tsx`: + +```typescript +"use client"; + +import React, { useState } from "react"; + +import Button from "./Button"; +import Input from "./Input"; + +interface SendPaymentFormProps { + onSubmit: (destination: string, amount: string) => void; +} + +const SendPaymentForm: React.FC = ({ onSubmit }) => { + const [destination, setDestination] = useState(""); + const [amount, setAmount] = useState(""); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + onSubmit(destination, amount); + }; + + return ( +
+
+ + setDestination(e.target.value)} + /> +
+
+ + setAmount(e.target.value)} + /> +
+ +
+ ); +}; + +export default SendPaymentForm; +``` + +### Designing responsive layouts with Tailwind CSS + +To create a responsive layout for our dapp, we'll use Tailwind CSS utility classes. Let's create a layout component that we can use across our pages. Edit the file `app/layout.tsx`: + +```typescript +import "./globals.css"; + +import { Inter } from "next/font/google"; +import type { Metadata } from "next"; +import React from "react"; + + +export const metadata: Metadata = { + title: "Stellar Payment DApp", + description: "Payment DApp built on Stellar", +}; + +interface LayoutProps { + children: React.ReactNode; +} + +const Layout: React.FC = ({ children }) => { + return ( + + +
+
+
+

Stellar Dapp

+
+
+
+
+
+
+ {children} +
+
+
+
+
+ + + ); +}; + +export default Layout; +``` + +Now, let's update our `app/page.tsx` file to use this layout and our new components: + +```typescript +"use client" + +import React from "react"; +import SendPaymentForm from "../components/SendPaymentForm"; + +export default function Home() { + const handleSendPayment = (destination: string, amount: string) => { + // We'll implement this function in the next section + console.log(`Sending ${amount} XLM to ${destination}`); + }; + + return ( +
+

Send Payment

+ +
+ ); +} +``` + +This setup provides a solid foundation for building the user interface of our Stellar dapp. In the next section, we'll integrate these components with the Stellar SDK to perform actual blockchain operations. + +## 4. Basic Concepts of Soroban Contracts + +Before we start integrating smart contract functionality into our Stellar dapp, let's understand the basic concepts of Soroban contracts. + +Soroban is a smart contract platform built on the Stellar network. It allows developers to write and deploy smart contracts that run on the Stellar blockchain. Soroban contracts are written in Rust and compiled to [XDR (External Data Representation)](/docs/learn/encyclopedia/data-format/xdr) for execution on the Stellar network. + +### Data Types + +Stellar supports a few data types that can be used in Soroban contracts and we need to do conversions from time to time between those types and the types we have in Javascript. The full list of primitive data types are explained [here](/docs/learn/encyclopedia/contract-development/types/built-in-types). + +### XDR + +Values that are passed to contracts and returned from contracts are serialized using XDR. XDR is a standard data serialization format used in Stellar to represent complex data structures. It is used to encode and decode data for transmission over the Stellar network. XDR is mostly represented in Javascript as string and can be converted to other types using the Stellar SDK. + +### Fees + +Gas fees like they are called in the ethereum network are charged differently here. When submitting different types of transactions, the type of fees paid are different. When submitting a transaction to the network that interacts with the network, a Base fee is paid together with the resource fee for the operation. The base fee is a fixed fee that is paid for every transaction on the network. The resource fee is a fee that is paid for the resources used by the operation and is calculated based on the resources used by the operation and the network's current resource price. + +Calculating these fees can be cumbersome but the Stellar SDK provides a way to calculate these fees using the `server.prepareTransaction` method which simulates the transaction, gets the appropriate fees and appends the correct fee settings to the transaction. + +### ABI or Spec + +The ABI or spec is a json file that contains the contract's interface. It defines the functions that can be called on the contract, their parameters, and return types. The ABI is used by clients to interact with the contract and execute its functions. The ABI is generated from the contract's source code and is used to compile the contract into XDR for execution on the Stellar network. + +ABI can be genrated for a contract using the [`stellar contract bindings`](/docs/tools/developer-tools/cli/stellar-cli#stellar-contract-bindings-json) command and can be used to interact with the contract. + +This ABI can also be generated as a typescript library to ease development in your DApp and we'll be looking it later in this guide + +## 5. Integrating with Stellar blockchain + +Now that we have our basic UI components in place, let's integrate them with the Stellar blockchain using the Stellar SDK. It is imperative to know that the Stellar blockchain has three major networks: + +- Public network (also called Mainnet): This is the main Stellar network where real transactions take place. +- Test network: This is a test environment for developers to test their applications without using real lumens. +- Futurenet network: This is a network for testing new features before they are deployed to the public network. + +For this guide, we'll be using the Test network to avoid using real lumens during development. Read more about the Stellar networks [here](https://developers.stellar.org/docs/learn/fundamentals/networks). + +### Setting up the Stellar SDK + +Below is a snippet that shows how to set up the Stellar SDK in your project. We will be using parts of it a lot in this guide so lets try to understand it. + +```typescript +import * as StellarSdk from "@stellar/stellar-sdk"; + +import { SorobanRpc } from "@stellar/stellar-sdk"; + +export const server = new SorobanRpc.Server("https://soroban-testnet.stellar.org"); // soroban testnet server + +const transaction = new StellarSdk.TransactionBuilder(account, { + fee: StellarSdk.BASE_FEE + networkPassphrase: StellarSdk.Networks.TESTNET, // Use appropriate network +}) +``` + +In the above snippet, we import the Stellar SDK and create a server instance for the Stellar Testnet. + +We also create a transaction builder instance with the appropriate network passphrase. The `BASE_FEE` is the minimum fee required for a transaction on the Stellar network. while the `Networks.TESTNET` is the network passphrase for the Stellar Testnet. When using the public network, you can replace `TESTNET` with `PUBLIC` or `FUTURENET` for the Futurenet network. + +### Interacting with the Stellar network + +If you are coding along this guide at this point, you should have a minimal web application with a form to send payments. Now, let's integrate this form with the Stellar SDK to send actual payments on the Stellar network. + +Before we proceed, please ensure that you have setup the Freighter wallet extension on your browser. You can download it [here](https://www.freighter.app). Also, ensure that you have lumens on the Testnet account you are using. You can get free lumens from the [Stellar Friendbot](https://laboratory.stellar.org/#account-creator?network=test). + +Now, let's update our `app/page` component to interact with the Stellar network: + +```typescript +"use client"; + +import React, { useState, useEffect } from "react"; +import SendPaymentForm from "../components/SendPaymentForm"; +import * as StellarSdk from "@stellar/stellar-sdk"; +import { SorobanRpc } from "@stellar/stellar-sdk"; +import { + isConnected, + setAllowed, + getPublicKey, + signTransaction, +} from "@stellar/freighter-api"; + +export default function Home() { + const [publicKey, setPublicKey] = useState(null); + + useEffect(() => { + const checkFreighter = async () => { + try { + const connected = await isConnected(); + if (connected) { + const pubKey = await getPublicKey(); + setPublicKey(pubKey); + } + } catch (error) { + console.error("Error checking Freighter connection:", error); + } + }; + + checkFreighter(); + }, []); + + const handleConnectWallet = async () => { + try { + await setAllowed(); + const pubKey = await getPublicKey(); + setPublicKey(pubKey); + } catch (error) { + console.error("Error connecting to Freighter:", error); + } + }; + + const handleSendPayment = async (destination: string, amount: string) => { + if (!publicKey) { + console.error("Wallet not connected"); + return; + } + + try { + const server = new SorobanRpc.Server("https://soroban-testnet.stellar.org"); + const sourceAccount = await server.getAccount(publicKey); + const transaction = new StellarSdk.TransactionBuilder(sourceAccount, { + fee: StellarSdk.BASE_FEE, + networkPassphrase: StellarSdk.Networks.TESTNET, + }) + .addOperation( + StellarSdk.Operation.payment({ + destination: destination, + asset: StellarSdk.Asset.native(), + amount: amount, + }) + ) + .setTimeout(30) + .build(); + + const signedTransaction = await signTransaction(transaction.toXDR(), { + networkPassphrase: StellarSdk.Networks.TESTNET, + }); + + const transactionResult = await server.sendTransaction( + StellarSdk.TransactionBuilder.fromXDR( + signedTransaction, + StellarSdk.Networks.TESTNET + ) + ); + + console.log("Transaction successful:", transactionResult); + alert("Payment sent successfully!"); + } catch (error) { + console.error("Error sending payment:", error); + alert("Error sending payment. Please check the console for details."); + } + }; + + return ( +
+

Send Payment

+ {publicKey ? ( + <> +

Connected: {publicKey}

+ + + ) : ( + + )} +
+ ); +} +``` + +In the updated `app/page` component, we added a `useEffect` hook to check if the Freighter wallet is connected and retrieve the public key. We also added a `handleConnectWallet` function to connect the wallet if it's not already connected. + +The `handleSendPayment` function now interacts with the Stellar network to send a payment. It retrieves the source account details, creates a payment transaction, signs the transaction using the Freighter wallet, and sends the transaction to the Stellar network. If the transaction is successful, it displays an alert to the user. + +Notice how we imported the `isConnected`, `setAllowed`, `getPublicKey`, and `signTransaction` functions from the `@stellar/freighter-api` library. These functions are used to interact with the Freighter wallet extension and sign transactions securely. + +:::tip + +Hurray! You have successfully integrated your Stellar dapp with the Stellar network. You can now send payments using the Freighter wallet extension on the Stellar Testnet. + +::: + +### Interacting with smart contracts + +In the above example, we sent a simple payment transaction using the `StellarSdk.Operation.payment` operation. However, Stellar also supports many other operations, one of which is `invokeHostFunction` operation which is used to interact with smart contracts on the Stellar network. + +We will be working with a deployed version of the [counter smart contract](https://github.com/stellar/soroban-examples/tree/main/events) on the Stellar Testnet. The smart contract has a single function `increment` which increments a counter value stored on the Stellar network. + +Create a new file `app/counter/page.tsx`: + +```typescript +"use client"; + +import { + BASE_FEE, + Contract, + Networks, + SorobanRpc, + Transaction, + TransactionBuilder, + xdr, +} from "@stellar/stellar-sdk"; +import React, { useEffect, useState } from "react"; +import { + getPublicKey, + isConnected, + signTransaction, +} from "@stellar/freighter-api"; + +import { ConnectButton } from "@/components/ConnectButton"; + +// Replace with your actual contract ID and network details +const CONTRACT_ID = "CC6MWZMG2JPQEENRL7XVICAY5RNMHJ2OORMUHXKRDID6MNGXSSOJZLLF"; +const NETWORK_PASSPHRASE = Networks.TESTNET; +const SOROBAN_URL = "https://soroban-testnet.stellar.org:443"; + +export default function CounterPage() { + const [publicKey, setPublicKey] = useState(null); + const [count, setCount] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + const checkWallet = async () => { + const connected = await isConnected(); + if (connected) { + const pubKey = await getPublicKey(); + setPublicKey(pubKey); + } + }; + + checkWallet(); + }, []); + + const handleIncrement = async () => { + if (!publicKey) { + console.error("Wallet not connected"); + return; + } + + setLoading(true); + + try { + const server = new SorobanRpc.Server(SOROBAN_URL); + const account = await server.getAccount(publicKey); + + const contract = new Contract(CONTRACT_ID); + // const instance = contract.getFootprint(); + + const tx = new TransactionBuilder(account, { + fee: BASE_FEE, + networkPassphrase: NETWORK_PASSPHRASE, + }) + .addOperation(contract.call("increment")) + .setTimeout(30) + .build(); + + const preparedTx = await server.prepareTransaction(tx); + + const signedXdr = await signTransaction(preparedTx.toEnvelope().toXDR("base64"), { + networkPassphrase: NETWORK_PASSPHRASE, + }); + + const signedTx = TransactionBuilder.fromXDR( + signedXdr, + NETWORK_PASSPHRASE + ) as Transaction; + + const txResult = await server.sendTransaction(signedTx); + + if (txResult.status !== "PENDING") { + throw new Error("Something went Wrong"); + } + const hash = txResult.hash; + let getResponse = await server.getTransaction(hash); + // Poll `getTransaction` until the status is not "NOT_FOUND" + + while (getResponse.status === "NOT_FOUND") { + console.log("Waiting for transaction confirmation..."); + getResponse = await server.getTransaction(hash); + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + + if (getResponse.status === "SUCCESS") { + // Make sure the transaction's resultMetaXDR is not empty + if (!getResponse.resultMetaXdr) { + throw "Empty resultMetaXDR in getTransaction response"; + } + } else { + throw `Transaction failed: ${getResponse.resultXdr}`; + } + + // Extract the new count from the transaction result + const returnValue = getResponse.resultMetaXdr + .v3() + .sorobanMeta() + ?.returnValue(); + if (returnValue) { + const newCount = returnValue.u32(); + setCount(newCount); + } + } catch (error) { + console.error("Error incrementing counter:", error); + alert( + "Error incrementing counter. Please check the console for details." + ); + } finally { + setLoading(false); + } + }; + + return ( +
+

+ Stellar Smart Contract Counter +

+ {publicKey ? ( +
+

Connected: {publicKey}

+

+ Current Count: {count === null ? "Unknown" : count} +

+ +
+ ) : ( + <> +

Please connect your Freighter wallet to use this app.

+ + + )} +
+ ); +} +``` + +In the above code snippet, we created a new page component `CounterPage` that interacts with the counter smart contract on the Stellar network. The `handleIncrement` function sends a transaction to the smart contract to increment the counter value. It then retrieves the updated counter value from the transaction result and displays it to the user. + +Notice how we used a different operation `contract.call("increment")` to interact with the smart contract. This operation is a facade for the `invokeHostFunction` operation on the Stellar network. We also used the `prepareTransaction` and `sendTransaction` methods to send the transaction to the network and retrieve the transaction result. + +`prepareTransaction` call is used to prepare a transaction for submission to the network. It simulates the transaction, then uses the appropriate resource fees and other params to create a transaction that is ready to be submitted to the network. + +`` is a helper button that connects the Freighter wallet when clicked like we described earlier. + +After calling the transaction to increment successfully, we need to poll and then call another method `server.getTransaction` to get the transaction result. The transaction result contains the new counter value which we extract and display to the user. + +The value gotten from the transaction result is stored in a form called `scval` due to the limited [number of types](/docs/learn/encyclopedia/contract-development/types/built-in-types) that exist in soroban today. This value is transmitted about in the form of `xdr` which can be converted to an `scVal` using the sdk. The value is then parsed as `u32` which is a 32-bit unsigned integer. We will learn more about converting these types when [working with contract specs](/docs/build/guides/conventions) + +:::tip + +Congratulations! You have successfully interacted with a smart contract on the Stellar network using your dapp. + +::: + +### Reading events from the Stellar network + +Events on Stellar are values emitted from contracts grouped by topics. These events are emitted when a contract is called and can be read by any client that is interested in the contract. Events are stored in the Stellar ledger and can be read by any client that is interested in the contract. + +In addition to sending transactions and interacting with smart contracts, you can also read events from the Stellar network using the Stellar SDK. This allows you to monitor account changes, transaction status, and other network events in real-time. + +This is made possible by using the `server.getEvents` method which allows you to query events based on topics. We will consider a simple example where we read events from the counter smart contract we interacted with earlier. + +We will be editing the `CounterPage` component to read events from the counter smart contract immediately the page loads to get the initial counter value and update instead of using "Unknown". Before we continue, please take a look at the [contract code](https://github.com/stellar/soroban-examples/blob/main/events/src/lib.rs). In the contract code, an event named `increment` is emitted whenever the `increment` function is called. It is published over 2 topics, `increment` and `COUNTER` and we need to listen to these topics to get the events. + +The topics are stored in a data type called `symbol` and we will need to convert both `increment` and `COUNTER` to `symbol` before we can use them in the [`server.getEvents`](https://developers.stellar.org/docs/data/rpc/api-reference/methods/getEvents) method. By default, soroban RPCs keep track of events for 24 hours and you can query events that happened within the last 24 hours, so if you need to store events for longer, you may need to make use of an [indexer](/docs/tools/developer-tools/data-indexers). + +To use events,we edit our counter page and add the following code: + +```typescript +useEffect(() => { + const checkWallet = async () => { + const connected = await isConnected(); + if (connected) { + const pubKey = await getPublicKey(); + setPublicKey(pubKey); + } + }; + checkWallet(); + getInitialCount(); +}, []); + +const getInitialCount = async () => { + try { + const topic1 = xdr.ScVal.scvSymbol("COUNTER").toXDR("base64"); + const topic2 = xdr.ScVal.scvSymbol("increment").toXDR("base64"); + const latestLedger = await server.getLatestLedger(); + const events = await server.getEvents({ + startLedger: latestLedger.sequence - 2000, + filters: [ + { + type: "contract", + contractIds: [CONTRACT_ID], + topics: [[topic1, topic2]], + }, + ], + limit: 20, + }); + setCount(events.events.map((e) => e.value.u32()).pop() || null); + } catch (error) { + console.error(error); + } +}; +``` + +In the above code, we use an RPC method called `getEvents` to query events from the Stellar network. We pass in the contract ID, topics, and other filters like the ledger to start searching from to 2000 ledgers away to get the events we are interested in. We then extract the counter value from the events and update the state accordingly. + +However, we had to convert the topics `COUNTER` and `increment` to `symbol` using the `xdr.ScVal.scvSymbol` and then convert them to XDR before we can use them in the `getEvents` method. This is because the topics are stored in the form of `symbol` and transmitted over XDR format to the network like we discussed earlier. Similarly, the value of the new count is sent over the network as XDR but the SDK helped us convert it to an `scVal` and then we parsed it as a `u32` to get the actual value. + +Source code for this program is available [here](https://github.com/myestery/stellar-dapp) + +Now, when the page loads, it will query the events from the Stellar network and update the counter value accordingly. + +## 6. Using Typescript Bindings + +The Stellar CLI comes with support for exporting a contract spec to a typescript library. This library is optimized for importing as an npm based module to your application. + +The library generated contains helper methods for calling each contract and also does automatic type conversion of the types for any contract method. + +### How to create the bindings library + +To achieve this, you need to + +- Have the [Stellar CLI](/docs/tools/developer-tools/cli/install-cli) installed. +- Have either source code or deployed contract ID of the contract. +- Know the network it was deployed to. + +#### Scenario 1: I have the Contract ID but no code + +In this scenario, we need to use the command [`stellar contract fetch`](/docs/tools/developer-tools/cli/stellar-cli#stellar-contract-fetch) to fetch the wasm code of the contract + +#### Scenario 2: I have the code + +The next step here is to build it to a wasm file using the [`stellar contract build`](/docs/tools/developer-tools/cli/stellar-cli#stellar-contract-build) command. + +### Generating the Library + +After getting the wasm, we can now run [`stellar contract bindings typescript`](/docs/tools/developer-tools/cli/stellar-cli#stellar-contract-bindings-typescript) to generate the library which is ready to be published to NPM. The library generated is suited for working with complex contracts. + +## 7. Common Pitfalls + +Below are a few common pitfalls that soroban DApp developers might run into + +### Data Type Conversions + +The data types in Javascript are different from the data types in soroban. When working with soroban contracts, you need to be aware of the data types and how to convert them to the types you are familiar with in Javascript. The Stellar SDK provides helper methods for converting between XDR and Javascript types in the `xdr` namespace. + +### Fees + +Calculating fees for transactions can be tricky. The Stellar SDK provides a way to calculate fees using the `server.prepareTransaction` method, which simulates the transaction and returns the appropriate fees. Fees are calculated in [stroops](/docs/learn/glossary#stroop) + +### SendTransaction and GetTransaction + +Results from a smart contract execution or any of the [valid transactions](/docs/learn/fundamentals/transactions/list-of-operations#extend-footprint-ttl) on soroban are not immediate. They are kept in a `PENDING` state until they are confirmed. You need to poll the `getTransaction` method to get the final result of the transaction. + +### State Archival + +State Archival is a characteristic of soroban contracts where some data stored on the ledger about the contract might be archived. This [guide](/docs/build/guides/archival) helps to understand how to work with state archival in DApps. + +### Data Retention + +A few things to note about data retention in soroban contracts: + +- Events Data can be queried within 24 hours of the event happening. So you may need an indexer to store events for longer periods. +- Transaction data is stored with a retention period of 1440 ledgers. This means after 1440 ledgers, the transaction data cannot be queried using the RPC. Again, you may need an indexer to store transaction data for longer periods.