Skip to main content

Overview

note

This tutorial walks through how to build an application with the js-stellar-sdk, to build with the Wallet SDK, please follow the Build a Wallet tutorial. To build with smart contracts, navigate to the Smart Contracts section.

In this tutorial, we'll walk through the steps needed to build a basic payment application on Stellar's Testnet. After this tutorial, you should have a good understanding of the fundamental Stellar concepts and a solid base for iterative development.

For this tutorial, we'll walk through the steps as we build a sample application we've called BasicPay, which will be used to showcase various features.

caution

Although BasicPay is a full-fledged application on Stellar's Testnet, it has been built solely to showcase Stellar functionality for the educational purposes of this tutorial, not to be copied, pasted, and used on Mainnet.

Project setup

Project requirements

To build a basic Stellar application, you'll need:

  • Application framework: we're using SvelteKit opting for JavaScript with JSDoc typing. SvelteKit is quite flexible and could be used for a lot, but we are mainly using it for its routing capabilities to minimize this being a "SvelteKit tutorial".
  • Frontend framework: we're using DaisyUI to simplify the use of Tailwind CSS.
  • A way to interact with the Stellar network: we're using the js-stellar-sdk, but you could use traditional fetch requests. The js-stellar-sdk is also used for building transactions to submit to the Stellar network.
  • A way to interact with the user's keypair: we're using the js-stellar-wallets SDK, but you can opt to use an existing wallet.
note

While we are using the above components to construct our application, we have done our best to write this tutorial in such a way that dependency on any one of these things is minimized. Ideally, you should be able to use the JavaScript code we've written and plug it into any other framework you'd like with minimal effort.

We've made the following choices during the development of BasicPay that you may also need to consider as you follow along:

  • We've designed this app for desktop. For the most part, the app is responsive to various screen sizes, but we have chosen not to go out of our way to prioritize the mobile user experience.
  • We have enabled the default DaisyUI "light" and "dark" themes, which should switch with the preferences of your device. There is no toggle switch enabled, though.
  • This is written as a client-side application. No server-side actions actually take place. If you are building an application with a backend and frontend, you will need to consider carefully which information lives where, especially when a user's secret key is involved.
  • We're deploying this as a static "single-page application" with Cloudflare Pages. Your own deployment decisions will have an impact on your configuration and build process.
  • The application is likely not as performant as it could be. Neither is it as optimized as it could be. We've tried to encapsulate the various functionalities in a way that makes sense to the developer reading the codebase, so there is some code duplication and things could be done in a "better" way.
  • We do some error handling, but not nearly as much as you would want for a real-world application. If something seems like it's not working, and you're not seeing an error, open your developer console, and you might be able to figure out what has gone wrong.
  • We have not implemented any automated testing. You'll probably want some for your application.
note

This tutorial is probably best viewed as "nearly comprehensive." We aren't going to walk you through each and every file in our codebase, and the files we do use to illustrate concepts in the tutorial may not be entirely present or explained. However, we will cover the basics, and point you to more complete examples in the codebase when applicable.

Dev helpers

  • Stellar Laboratory: an experimental playground to interact with the Stellar network
  • Friendbot: a bot that funds accounts with 10,000 fake XLM on Stellar's Testnet; you can fund your account by going to https://friendbot.stellar.org/?addr=G...
  • Testnet toml file: an example stellar.toml file that demonstrates what information an anchor might publish
  • BasicPay dev helpers: if you're using the BasicPay application, we've created a few helpful tools to help you explore its functionality

Getting started

Here are the steps we've taken to start building BasicPay. Feel free to be inspired and customize these directions as you see fit. The entire BasicPay codebase is freely open and available on GitHub for reference.

note

This part of the tutorial will need a large helping of "your mileage may vary." We will outline what steps we've taken for our deployment situation, but you will want to review what options are needed for your environment(s).

Install frameworks

The first thing we'll need to do is create a SvelteKit app, using npm, we are using v18.x of nodejs.

npm create svelte@latest my-basic-payment-app

This will walk you through the SvelteKit creation process, asking you about the various options. We've chosen the following options:

  • Which Svelte app template? Skeleton project
  • Are you type checking with TypeScript? Yes, using JavaScript with JSDoc comments
  • Select additional options Add ESLint for code linting; Add Prettier for code formatting

After this process, the scaffolding for your application will live inside the my-basic-payment-app directory. You can cd into that directory and add some UI dependencies.

cd my-basic-payment-app
npm install --save-dev svelte-preprocess tailwindcss autoprefixer postcss @sveltejs/adapter-static \
@tailwindcss/typography \
daisyui svelte-feather-icons

Before we configure anything, we'll need to generate our tailwind.config.js and postcss.config.js files.

npx tailwindcss init -p

Now, we will require a bit of configuration to make all those components work together. First, modify your svelte.config.js file:

/svelte.config.js
import preprocess from "svelte-preprocess";
import adapter from "@sveltejs/adapter-static";

/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
// Note: Your `dapter` configuration may need customizations depending
// on how you are building and deploying your application.
adapter: adapter({
fallback: "index.html",
}),
},
preprocess: [
preprocess({
postcss: true,
}),
],
};

export default config;

Next, you can configure the tailwind.config.js file.

  1. Import the daisyui and typography plugins
  2. Configure our content paths (you may need to modify these values depending on your project structure)
  3. Add the daisyui plugin after any officialy @tailwindcss plugins (only typography in our example)
/tailwind.config.js
const daisyui = require("daisyui");
const typography = require("@tailwindcss/typography");

/** @type {import('tailwindcss').Config} */
export default {
content: [
"./src/routes/**/*.{html,js,svelte,ts}",
"./src/routes/**/**/*.{html,js,svelte,ts}",
"./src/lib/components/**/*.{html,js,svelte,ts}",
],
plugins: [typography, daisyui],
};

Add your tailwind directives to your app's main CSS file.

/src/app.postcss
@tailwind base;
@tailwind components;
@tailwind utilities;

Then import the CSS file into your base SvelteKit layout (you may need to create this file).

/src/routes/+layout.svelte
<script>
import "../app.postcss";
</script>

<slot />

We also created a /src/routes/+layout.js file to configure our application as only client-side. This means the app will be delivered to the client as unrendered HTML and JavaScript.

/src/routes/+layout.js
// Disable pre-rendering of pages during build-time
export const prerender = false;
// Disable server-side rendering
export const ssr = false;

Your SvelteKit project is now configured and ready to run!

npm run dev

Stellar dependencies

To work with the Stellar network, datastructures, and locally stored keypairs, we're going to install and configure a few more dependencies.

# Stellar SDKs
npm install --save-dev stellar-sdk @stellar/wallet-sdk
# We will need some polyfills to make things available client-side
npm install --save-dev @esbuild-plugins/node-globals-polyfill @esbuild-plugins/node-modules-polyfill \
path @rollup/plugin-inject buffer svelte-local-storage-store uuid

We will use a window.js file to inject Buffer into our client-side code, since that's required by some parts of the stellar-sdk.

/src/lib/window.js
import { browser } from "$app/environment";
import { Buffer } from "buffer";

if (browser) {
window.Buffer = Buffer;
} else {
globalThis.Buffer = Buffer;
globalThis.window = {};
}
export default globalThis;

The actual "injection" takes place in our vite.config.js file.

/vite.config.js
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
import { NodeGlobalsPolyfillPlugin } from "@esbuild-plugins/node-globals-polyfill";
import inject from "@rollup/plugin-inject";
import path from "path";

export default defineConfig({
plugins: [sveltekit()],
optimizeDeps: {
esbuildOptions: {
define: {
global: "globalThis",
},
plugins: [
NodeGlobalsPolyfillPlugin({
buffer: true,
}),
],
},
},
build: {
rollupOptions: {
plugins: [
inject({
window: path.resolve("src/lib/window.js"),
}),
],
},
},
ssr: {
noExternal: ["@stellar/wallet-sdk", "@albedo-link/intent"],
},
});

That should take care of everything you need! If you've followed these steps, you now have running client-side-only application that's ready to build out an application that interacts with the Stellar network! Way to go!

Next up, we'll look at how we register a user and create their account on the Stellar network.