From 4f1198cfde2df402c0e74f1145828423c39e29ea Mon Sep 17 00:00:00 2001 From: Elliot Voris Date: Wed, 29 Nov 2023 13:01:38 -0600 Subject: [PATCH 1/7] Revert "Update getting started tutorial to use an Astro template (#642)" (#658) This reverts commit 512b1f46506b7edc788bc6e93a0e1f6d101d22ae. --- docs/getting-started/create-an-app.mdx | 488 ++++++++++++++++++++ docs/getting-started/deploy-incrementor.mdx | 221 +-------- docs/getting-started/deploy-to-testnet.mdx | 117 +---- docs/getting-started/hello-world.mdx | 203 ++++---- docs/getting-started/storing-data.mdx | 137 +++++- docs/getting-started/wrapping-up.mdx | 151 ------ nginx/includes/redirects.conf | 1 - src/pages/index.js | 18 +- 8 files changed, 772 insertions(+), 564 deletions(-) create mode 100644 docs/getting-started/create-an-app.mdx delete mode 100644 docs/getting-started/wrapping-up.mdx diff --git a/docs/getting-started/create-an-app.mdx b/docs/getting-started/create-an-app.mdx new file mode 100644 index 00000000..a20c5aeb --- /dev/null +++ b/docs/getting-started/create-an-app.mdx @@ -0,0 +1,488 @@ +--- +sidebar_position: 6 +title: 5. Create an App +description: Make a frontend web app that interacts with your smart contracts. +--- + +With two smart contracts deployed to a public network, you can now create a web app that interacts with them via RPC calls. Let's get started. + +## Initialize a frontend toolchain + +You can build a Soroban app with any frontend toolchain or integrate it into any existing full-stack app. For this tutorial, we're going to use [Astro](https://astro.build/). Astro works with React, Vue, Svelte, any other UI library, or no UI library at all. In this tutorial, we're not using a UI library. The Soroban-specific parts of this tutorial will be similar no matter what frontend toolchain you use. + +If you're new to frontend, don't worry. We won't go too deep. But it will be useful for you to see and experience the frontend development process used by Soroban apps. We'll cover the relevant bits of JavaScript and Astro, but teaching all of frontend development and Astro is beyond the scope of this tutorial. + +Let's get started. + +You're going to need [Node.js](https://nodejs.org/en/download/package-manager/) v18.14.1 or greater. If you haven't yet, install it now. + +Then we want to initialize the current directory, `soroban-tutorial`, as an Astro project, but Astro doesn't like that. It wants to create a new directory. So let's go ahead and do that, then move all the contents of the new directory into its parent directory. From the original `soroban-tutorial` directory, run: + +```bash +npm create astro@4.0.1 soroban-tutorial -- --template basics --install --no-git --typescript strictest +``` + +This will take a little while, as the `--install` option automatically installs the dependencies. Once it's done, let's move the contents of the new nested folder into the project root. Other project organization strategies are possible, but we find that it causes no problems to have the Node-specific web app stuff live right alongside the Rust-specific smart contract stuff and that keeping it all in the root just makes things simpler. + +```bash +mv soroban-tutorial/* . +mv soroban-tutorial/.vscode . +cat soroban-tutorial/.gitignore >> .gitignore +rm soroban-tutorial/.gitignore +rmdir soroban-tutorial +``` + +This is a good time to commit your changes so that later on, you can clearly see the differences between what came from Astro's `basics` template and the Soroban-specific stuff we're going to add. + +```bash +git add . +git commit -m "Initialize Astro project" +``` + +## Generate an NPM package for the Hello World contract + +Before we even open the new frontend files, let's generate an NPM package for the Hello World contract. This is our suggested way to interact with contracts from frontends. These generated libraries work with any JavaScript project (not a specific UI like React), and make it easy to work with some of the trickiest bits of Soroban, like encoding [XDR](https://soroban.stellar.org/docs/fundamentals-and-concepts/fully-typed-contracts). + +This is going to use the CLI command `soroban contract bindings typescript`: + +```bash +soroban contract bindings typescript \ + --network testnet \ + --contract-id $(cat .soroban/hello-id) \ + --output-dir node_modules/hello-soroban-client +``` + +We attempt to keep the code in these generated libraries readable, so go ahead and look around. Open up the new `hello-soroban-client` directory in your editor. If you've built or contributed to Node projects, it will all look familiar. You'll see a `package.json` file, a `src` directory, a `tsconfig.json`, and even a README. The README is a great place to start. Go ahead and give it a read. + +As it says, when using local libraries, we've had the [most success](https://github.com/stellar/soroban-example-dapp/pull/117#discussion_r1232873560) when generating them directly into the `node_modules` folder, and leaving them out of the `dependencies` section. Yes, this is surprising, but it works the best. + +Let's update the `package.json` in your `soroban-tutorial` project with a `postinstall` script to make sure the generated library stays up-to-date: + +```diff title="package.json" + "scripts": { + ... +- "astro": "astro" ++ "astro": "astro", ++ "postinstall": "soroban contract bindings typescript --network testnet --contract-id $(cat .soroban/hello-id) --output-dir node_modules/hello-soroban-client" + } +``` + +### Call the contract from the frontend + +Now let's open up `src/pages/index.astro` and add some code to call the contract. We'll start by importing the generated library: + +```diff title="src/pages/index.astro" + --- + import Layout from '../layouts/Layout.astro'; + import Card from '../components/Card.astro'; ++import { Contract, networks } from 'hello-soroban-client'; ++ ++const greeter = new Contract({ ++ ...networks.testnet, ++ rpcUrl: 'https://soroban-testnet.stellar.org', // from https://soroban.stellar.org/docs/reference/rpc#public-rpc-providers ++}); ++ ++const greeting = await greeter.hello({ to: 'Soroban' }); + --- +``` + +Then find the `

` tag and replace its contents with the greeting: + +```diff title="src/pages/index.astro" +-

Welcome to Astro

++

{greeting.join(' ')}

+``` + +Now start the dev server: + +```bash +npm run dev +``` + +And open [http://localhost:4321](http://localhost:4321) in your browser. You should see the greeting from the contract! + +You can try updating the `{ to: 'Soroban' }` argument. When you save the file, the page will automatically update. + +### What's happening here? + +If you inspect the page (right-click, inspect) and refresh, you'll see a couple interesting things: + +- The "Network" tab shows that there are no Fetch/XHR requests made. But RPC calls happen via Fetch/XHR! So how is the frontend calling the contract? +- There's no JavaScript on the page. But we just wrote some JavaScript! How is it working? + +This is part of Astro's philosophy: the frontend should ship with as few assets as possible. Preferably zero JavaScript. When you put JavaScript in the [frontmatter](https://docs.astro.build/en/core-concepts/astro-components/), Astro will run it at build time, and then replace anything in the `{...}` curly brackets with the output. + +When using the development server with `npm run dev`, it runs the frontmatter code on the server, and injects the resulting values into the page on the client. + +You can try building to see this more dramatically: + +```bash +npm run build +``` + +Then check the `dist` folder. You'll see that it built an HTML and CSS file, but no JavaScript. And if you look at the HTML file, you'll see a static "Hello Soroban" in the `

`. + +During the build, Astro made a single call to your contract, then injected the static result into the page. This is great for contract methods that don't change, but probably won't work for most contract methods. Let's integrate with the `incrementor` contract to see how to handle interactive methods in Astro. + +## Call the incrementor contract from the frontend + +While `hello` is a simple view-only/read method, `increment` changes on-chain state. This means that someone needs to sign the transaction. So we'll need to add transaction-signing capabilities to the frontend. + +The way signing works in a browser is with a _wallet_. Wallets can be web apps, browser extensions, standalone apps, or even separate hardware devices. + +Right now, the wallet that best supports Soroban is [Freighter](../reference/freighter.mdx). It is available as a Firefox Add-on, as well as extensions for Chrome and Brave. Go ahead and [install it now](https://freighter.app). + +Once it's installed, open it up by clicking the extension icon. If this is your first time using Freighter, you will need to create a new wallet. Go through the prompts to create a password and save your recovery passphrase. + +Go to Settings (the gear icon) → Preferences and toggle the switch to Enable Experimental Mode. Then go back to its home screen and select "Test Net" from the top-right dropdown. Finally, if it shows the message that your Stellar address is not funded, go ahead and click the "Fund with Friendbot" button. + +Now you're all set up to use Freighter as a user, and you can add it to your app. + +### Add Freighter + +We're going to add a "Connect" button to the page that opens Freighter and prompts the user to give your web page permission to use Freighter. Once they grant this permission, the "Connect" button will be replaced with a message saying, "Signed in as [their public key]". + +First, add [@stellar/freighter-api](https://www.npmjs.com/package/@stellar/freighter-api) as a dependency: + +```bash +npm install @stellar/freighter-api +``` + +Then we need to work around a bug in NPM—adding a new dependency with `npm install [new dependency]` doesn't run the `postinstall` hook, the way that `npm install` does. But it does run the cleanup logic that removes "incorrect" folders like `node_modules/hello-soroban-client`. So you either need to run `npm i` (a shortcut for `npm install`), or `postinstall` directly: + +```bash +npm run postinstall +``` + +Now let's add a new component to the `src/components` directory called `ConnectFreighter.astro` with the following contents: + +```html title="src/components/ConnectFreighter.astro" +
+
+ +
+
+ + + + +``` + +Some of this may look surprising. ` - - -``` - -Some of this may look surprising. `