Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Update getting-started for 20.0.0-rc.4.1 cli #636

Merged
merged 24 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e0c0fe0
Updates to setup.mdx
elizabethengelman Oct 26, 2023
3b114c4
Add CLI for testnet configuration to Setup
elizabethengelman Oct 26, 2023
6a8824d
Updates to hello-world.mdx
elizabethengelman Oct 24, 2023
3fd4f7c
Small edits in storing-data.mdx
elizabethengelman Oct 25, 2023
6e89a0a
Add high_expiration_watermark argument to bump in incrementor
elizabethengelman Oct 25, 2023
b5c05d0
Move deploy-to-testnet after hello-world to allow the user to interac…
elizabethengelman Oct 26, 2023
6bdaef3
Add Optimizing Builds to hello-world
elizabethengelman Oct 26, 2023
535c9bc
Update storing-data to remove sandbox interation
elizabethengelman Oct 26, 2023
be94c88
Add a deploy-incrementor-to-testnet step
elizabethengelman Oct 26, 2023
a3aaadb
Update position of Create an App
elizabethengelman Oct 26, 2023
0d2cece
Apply suggestions from code review
elizabethengelman Nov 1, 2023
387cbb7
Apply suggestions from code review
elizabethengelman Nov 1, 2023
eedfa14
Update create-an-app.mdx
elizabethengelman Nov 1, 2023
81663c3
Fix typo
elizabethengelman Nov 1, 2023
24afe84
Add a mv command for .soroban dir when reorganizing to a multi-contra…
elizabethengelman Nov 1, 2023
8d496b2
Apply mdx prettier updates
elizabethengelman Nov 1, 2023
514e4d3
Update astro port in create-an-app.mdx
elizabethengelman Nov 1, 2023
e24108f
Apply suggestions from code review
elizabethengelman Nov 2, 2023
f11590a
Add .mdx to end of internal markdown links for docusaurus magic
elizabethengelman Nov 2, 2023
92b2c3d
Make sure there are new lines before and after ::: tags
elizabethengelman Nov 2, 2023
9da4250
Some additional edits/improvements
elizabethengelman Nov 2, 2023
65eedab
Mention that Freighter is available as a firefox add-on
elizabethengelman Nov 2, 2023
17126e3
Update the deploy-incrementor url
elizabethengelman Nov 6, 2023
6c5d4aa
Apply prettier updates
elizabethengelman Nov 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 47 additions & 90 deletions docs/getting-started/create-an-app.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
sidebar_position: 5
title: 4. Create an App
sidebar_position: 6
title: 5. Create an App
description: Make a frontend web app that interacts with your smart contracts.
---

Expand All @@ -16,7 +16,7 @@ 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 their parent directory:
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 [email protected] soroban-tutorial -- --template basics --install --no-git --typescript strictest
Expand All @@ -43,82 +43,35 @@ git commit -m "Initialize Astro project"

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`. Unfortunately, the version of `bindings typescript` packaged with CLI v0.9.4 has some bugs, and the fix can't be released yet because the `main` branch of the CLI is broken with futurenet. To work around this, we're going to install a pinned version of the CLI from a fixed-and-still-futurenet-compatible fork. Create a directory called `.cargo` (with the dot; it's a hidden folder):

mkdir .cargo

Then add one file to it, `config.toml`. Paste these contents into it:

```toml
[alias] # command aliases
install_soroban = "install --git https://github.com/AhaLabs/soroban-tools --branch smartdeploy --root ./target soroban-cli --debug"
```

Now install the pinned version by using the alias you just set up:

cargo install_soroban

This will take a couple minutes; it builds a local version from the `smartdeploy` branch into `target/bin/soroban`. Once it's done, check that it worked:

```bash
ls target/bin/soroban
```

And check the version info of this `smartdeploy` install:

```bash
./target/bin/soroban --version
```

If you want, you can add `./target/bin/` [to your PATH](https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path), so that anytime you're in a project with a locally-installed version of `soroban` in its `target/bin` directory, you'll automatically use it (rather than your global version) when you just type `soroban`. For this project, let's also add a `soroban` script in the root of the project that automatically installs the pinned version if it's not there, then uses it. This will make it easier for your collaborators to work with you. Create a file called just `soroban` and paste the following contents:
This is going to use the CLI command `soroban contract bindings typescript`:

```bash
#!/bin/bash
if [ ! -f ./target/bin/soroban ]; then
cargo install_soroban
fi
./target/bin/soroban "$@" # `$@` expands to all arguments passed to this script
```

Make sure it's executable:

```bash
chmod +x soroban
```

Ok, now you can finally generate that NPM package:

```bash
./soroban contract bindings typescript \
soroban contract bindings typescript \
--network testnet \
--contract-id $(cat .soroban/hello-id) \
--output-dir hello-soroban-client
--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. Go ahead and move this new library there:

```bash
mv hello-soroban-client node_modules
```
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.

And then 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:
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
```diff title="package.json"
ElliotFriend marked this conversation as resolved.
Show resolved Hide resolved
"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"
+ "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
```diff title="src/pages/index.astro"
---
import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro';
Expand All @@ -135,7 +88,7 @@ Now let's open up `src/pages/index.astro` and add some code to call the contract

Then find the `<h1>` tag and replace its contents with the greeting:

```diff
```diff title="src/pages/index.astro"
-<h1>Welcome to <span class="text-gradient">Astro</span></h1>
+<h1><span class="text-gradient">{greeting.join(' ')}</span></h1>
```
Expand All @@ -146,7 +99,7 @@ Now start the dev server:
npm run dev
```

And open [http://localhost:3000](http://localhost:3000) in your browser. You should see the greeting from the contract!
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.

Expand Down Expand Up @@ -177,10 +130,11 @@ While `hello` is a simple view-only/read method, `increment` changes on-chain st

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's a Chrome extension. Go ahead and [install it now](https://freighter.app).
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, go to Settings (the gear icon) → Preferences and toggle the switch to Enable Experimental Mode. Then go back to its home screen and select "Future 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.
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.

Expand All @@ -202,7 +156,7 @@ npm run postinstall

Now let's add a new component to the `src/components` directory called `ConnectFreighter.astro` with the following contents:

```html
```html title="src/components/ConnectFreighter.astro"
<div id="freighter-wrap" class="wrap" aria-live="polite">
<div class="ellipsis">
<button data-connect aria-controls="freighter-wrap">Connect</button>
Expand Down Expand Up @@ -270,7 +224,7 @@ Before we add this to our index page, let's make the buttons look better. Open `

<!-- prettier-ignore-start -->
<!-- Astro uses tabs. It's not worth fighting or mentioning, let's just make the pasted code look good with the rest-->
```css
```css title="layouts/Layout.astro"
button {
border: 1px solid rgb(var(--accent));
background-color: #23262d;
Expand Down Expand Up @@ -302,7 +256,7 @@ This copies the styles from the `Card` components that Astro included in the tem

Now we can import the component in the frontmatter of `pages/index.astro`:

```diff
```diff title="pages/index.astro"
---
import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro';
Expand All @@ -313,7 +267,7 @@ Now we can import the component in the frontmatter of `pages/index.astro`:

And add it right below the `<h1>`:

```diff
```diff title="pages/index.astro"
<h1><span class="text-gradient">{greeting.join(' ')}</span></h1>
+<ConnectFreighter />
```
Expand All @@ -330,11 +284,11 @@ Now you're ready to sign the call to `increment`!

### Call `increment`

We're going to generate a contract client for the incrementor contract with a similar command to the one we used before. Let's move the `hello` bindings generation to its own script, add this one, and call them both from `postinstall` using a double ampersand ([&&](https://stackoverflow.com/a/25669618/249801)):
We're going to generate a contract client for the incrementor contract with a similar command to the one we used before. Let's move the `hello` bindings generation to its own script, add one for incrementor, and call them both from `postinstall` using a double ampersand ([&&](https://stackoverflow.com/a/25669618/249801)):

```json
"bindings:hello": "./soroban contract bindings typescript --network testnet --contract-id $(cat .soroban/hello-id) --output-dir node_modules/hello-soroban-client",
"bindings:incrementor": "./soroban contract bindings typescript --network testnet --contract-id $(cat .soroban/incrementor-id) --output-dir node_modules/incrementor-client",
```json title="package.json"
"bindings:hello": "soroban contract bindings typescript --network testnet --contract-id $(cat .soroban/hello-id) --output-dir node_modules/hello-soroban-client",
"bindings:incrementor": "soroban contract bindings typescript --network testnet --contract-id $(cat .soroban/incrementor-id) --output-dir node_modules/incrementor-client",
"postinstall": "npm run bindings:hello && npm run bindings:incrementor"
```

Expand All @@ -346,14 +300,19 @@ npm i

Now we can import from `incrementor-client` and start using it. We'll again create a new Astro component. Create a new file at `src/components/Counter.astro` with the following contents:

```html
```html title="src/components/Counter.astro"
<strong>Incrementor</strong><br />
Current value: <strong id="current-value" aria-live="polite">???</strong><br />
<br />
<button data-increment aria-controls="current-value">Increment</button>

<script>
import { increment } from "incrementor-client";
import { Contract, networks } from "incrementor-client";

const incrementor = new Contract({
...networks.testnet,
rpcUrl: "https://soroban-testnet.stellar.org", // from https://soroban.stellar.org/docs/reference/rpc-list#sdf-futurenet-and-testnet-only
});

const button = document.querySelector("[data-increment]");
const currentValue = document.querySelector("#current-value");
Expand All @@ -365,7 +324,7 @@ Current value: <strong id="current-value" aria-live="polite">???</strong><br />
currentValue.innerHTML +
'<span class="visually-hidden"> – updating…</span>';

const newValue = await increment();
const newValue = await incrementor.increment();

// Only use `innerHTML` with contract values you trust!
// Blindly using values from an untrusted contract opens your users to script injection attacks!
Expand All @@ -385,7 +344,7 @@ Let's add styles for `visually-hidden` and `loading` class. In `layouts/Layout.a

<!-- prettier-ignore-start -->
<!-- Astro uses tabs. It's not worth fighting or mentioning, let's just make the pasted code look good with the rest-->
```css
```css title="layouts/Layout.astro"
button:is(:disabled).loading {
background: linear-gradient(-45deg, #ffffff44, #ffffff22);
background-size: 200%;
Expand Down Expand Up @@ -413,19 +372,19 @@ button:is(:disabled).loading {

Now let's use this component. In `pages/index.astro`, first import it:

```diff
```diff title="pages/index.astro"
---
import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro';
import ConnectFreighter from '../components/ConnectFreighter.astro';
+import Counter from '../components/Counter.astro';
import { hello } from 'hello-soroban-client';
import { Contract, networks } from "hello-soroban-client";
...
```

Then use it. Let's replace the contents of the `instructions` paragraph with it:

```diff
```diff title="pages/index.astro"
<p class="instructions">
- To get started, open the directory <code>src/pages</code> in your project.<br />
- <strong>Code Challenge:</strong> Tweak the "Welcome to Astro" message above.
Expand All @@ -435,8 +394,7 @@ Then use it. Let's replace the contents of the `instructions` paragraph with it:

Check the page; if you're still running your dev server, it should have already updated. Click the "Increment" button; you should see a Freighter confirmation. Confirm, and... the value updates! 🎉

There's obviously some functionality missing, though. For example, that `???` is a bummer. But our `incrementor` contract doesn't give us a way to query the
current value without also updating it.
There's obviously some functionality missing, though. For example, that `???` is a bummer. But our `incrementor` contract doesn't give us a way to query the current value without also updating it.

Before you try to update it, let's streamline the process around building, deploying, and generating clients for contracts.

Expand All @@ -446,7 +404,7 @@ Right now, the `postinstall` script assumes that you already have a `.soroban` d

First, let's add a `clean` script that removes the `.soroban` directory to make it easy to go back to how collaborators will experience this repository when they first clone it. We'll also remove the `node_modules/.vite` directory, which is where Astro caches its build artifacts ([Vite](https://vitejs.dev/) is a build tool [used by Astro](https://docs.astro.build/en/reference/configuration-reference/#vite)). Add the following to the `scripts` section of `package.json`:

```json
```json title="package.json"
"scripts": {
"clean": "rm -rf .soroban node_modules/.vite",
...
Expand All @@ -455,21 +413,21 @@ First, let's add a `clean` script that removes the `.soroban` directory to make

Next, let's add a `setup` script that builds your contracts, then checks if the `.soroban` folder is present, and if not, creates and funds the `alice` identity and deploys your contracts. This is a lot for a single NPM script, so we've broken it into a few to make it a little more legible. Add the following to the `scripts` section of `package.json`:

```json
```json title="package.json"
"scripts": {
...
"create_deployer": "./soroban config identity generate alice && ./soroban config identity fund alice --network testnet",
"deploy:hello": "./soroban contract deploy --wasm target/wasm32-unknown-unknown/release/hello_soroban.wasm --source alice --network testnet > .soroban/hello-id",
"deploy:incrementor": "./soroban contract deploy --wasm target/wasm32-unknown-unknown/release/incrementor.wasm --source alice --network testnet > .soroban/incrementor-id;",
"create_deployer": "soroban config identity generate alice && soroban config identity fund alice --network testnet",
"deploy:hello": "soroban contract deploy --wasm target/wasm32-unknown-unknown/release/hello_soroban.wasm --source alice --network testnet > .soroban/hello-id",
"deploy:incrementor": "soroban contract deploy --wasm target/wasm32-unknown-unknown/release/incrementor.wasm --source alice --network testnet > .soroban/incrementor-id;",
"deploy": "npm run deploy:hello && npm run deploy:incrementor",
"setup": "./soroban contract build && if [ ! -d .soroban ]; then npm run create_deployer && npm run deploy; fi",
"setup": "soroban contract build && if [ ! -d .soroban ]; then npm run create_deployer && npm run deploy; fi",
...
}
```

Finally, let's add a `reset` that calls both in order:

```json
```json title="package.json"
"scripts": {
...
"reset": "npm run clean && npm run setup",
Expand All @@ -481,9 +439,8 @@ Now anytime you make changes to your contracts, you can run `npm run reset` to b

You can also update the `postinstall` script to check for the existence of `.soroban` and automatically `npm run setup` if it's not found:

```json
"postinstall": "if [ ! -d .soroban ]; then npm run setup; fi && npm run bindings:hello && npm run bindings:incrementor"
"
```json title="package.json"
"postinstall": "if [ ! -d .soroban ]; then npm run setup; fi && npm run bindings:hello && npm run bindings:incrementor",
```

## Take it further
Expand Down
Loading