You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
21
21
22
-
We want to initialize our current project as an Astro project. To do this, we can again turn to the `stellar contract init` command, which has a `--frontend-template` flag that allows us to pass the url of a frontend template repository. As we learned in [Storing Data](../smart-contracts/getting-started/storing-data.mdx#adding-the-increment-contract), `stellar contract init` will not overwrite existing files, and is safe to use to add to an existing project.
22
+
We want to initialize our current project as an Astro project. To do this, we can clone a template. You can find Soroban templates on GitHub by [searching for repositories that start with "soroban-template-"](https://github.com/search?q=%22soroban-template-%22&type=repositories). For this tutorial, we'll use [stellar/soroban-template-astro](https://github.com/stellar/soroban-template-astro). We'll also use a tool called [degit](https://github.com/Rich-Harris/degit) to clone the template without its git history. This will allow us to set it up as our own git project.
23
23
24
-
From our `soroban-hello-world` directory, run the following command to add the Astro template files.
24
+
Since you have `node` and its package manager `npm` installed, you also have `npx`. Make sure you're no longer in your `soroban-hello-world` directory and then run:
git commit -m "first commit: initialize from stellar/soroban-template-astro"
29
32
```
30
33
31
-
This will add the following to your project, which we'll go over in more detail below.
34
+
This project has the following directory structure, which we'll go over in more detail below.
32
35
33
36
```bash
37
+
├── contracts
38
+
│ ├── hello_world
39
+
│ └── increment
34
40
├── CONTRIBUTING.md
41
+
├── Cargo.toml
42
+
├── Cargo.lock
35
43
├── initialize.js
36
44
├── package-lock.json
37
45
├── package.json
38
46
├── packages
39
47
├── public
40
-
│ └── favicon.svg
41
48
├── src
42
49
│ ├── components
43
50
│ │ └── Card.astro
@@ -49,6 +56,8 @@ This will add the following to your project, which we'll go over in more detail
49
56
└── tsconfig.json
50
57
```
51
58
59
+
The `contracts` are the same ones you walked through in the previous steps of the tutorial.
60
+
52
61
## Generate an NPM package for the Hello World contract
53
62
54
63
Before we 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](../../learn/encyclopedia/contract-development/types/fully-typed-contracts.mdx).
@@ -91,29 +100,26 @@ Let's take a look at the contents of the `.env` file:
91
100
92
101
```
93
102
# Prefix with "PUBLIC_" to make available in Astro frontend files
94
-
PUBLIC_SOROBAN_NETWORK_PASSPHRASE="Standalone Network ; February 2017"
# env vars that begin with PUBLIC_ will be available to the client
101
-
PUBLIC_SOROBAN_RPC_URL=$SOROBAN_RPC_URL
106
+
STELLAR_ACCOUNT="me"
107
+
STELLAR_NETWORK="standalone"
102
108
```
103
109
104
110
This `.env` file defaults to connecting to a locally running network, but we want to configure our project to communicate with Testnet, since that is where we deployed our contracts. To do that, let's update the `.env` file to look like this:
105
111
106
112
```diff
107
113
# Prefix with "PUBLIC_" to make available in Astro frontend files
108
-
-PUBLIC_SOROBAN_NETWORK_PASSPHRASE="Standalone Network ; February 2017"
109
-
+PUBLIC_SOROBAN_NETWORK_PASSPHRASE="Test SDF Network ; September 2015"
In the code above, we created an instance of the kit and two simple functions that will take care of "setting" and "loading" the public key of the user. This lets us use the user's public key elsewhere in our code. The kit is started with Freighter as the default wallet, and the Testnet network as the default network. You can learn more about how the kit works in [the StellarWalletsKit documentation](https://stellarwalletskit.dev/)
288
+
In the code above, we instantiate the kit with desired settings and export it. We also wrap some kit functions and add custom functionality, such as augmenting the kit by allowing it to remember which wallet options was selected between page refreshes (that's the `localStorage` bit). The kit requires a `selectedWalletId` even before the user selects one, so we also work around this limitation, as the code comment explains. You can learn more about how the kit works in [the StellarWalletsKit documentation](https://stellarwalletskit.dev/)
256
289
257
-
Now we're going to add a "Connect" button to the page which will open the kit's builtin modal, and prompt the user to use their preferred wallet. Once the user picks their preferred wallet and grants permission to accept requests from the website, we will fetch the public key and the "Connect" button will be replaced with a message saying, "Signed in as [their public key]".
290
+
Now we're going to add a "Connect" button to the page which will open the kit's built-in modal, and prompt the user to use their preferred wallet. Once the user picks their preferred wallet and grants permission to accept requests from the website, we will fetch the public key and the "Connect" button will be replaced with a message saying, "Signed in as [their public key]".
258
291
259
292
Now let's add a new component to the `src/components` directory called `ConnectWallet.astro` with the following content:
@@ -325,7 +376,7 @@ And all the `script` declarations get bundled together and included intelligentl
325
376
326
377
You can read more about this in [Astro's page about client-side scripts](https://docs.astro.build/en/guides/client-side-scripts/).
327
378
328
-
The code itself here is pretty self-explanatory. We import the wallets kit from the file we created before. Then, when the user clicks on the button, we launch the built-in modal do display to the user connection options. Once the user picks their preferred wallet, we set it as the wallets kit's default wallet before requesting and saving the address.
379
+
The code itself here is pretty self-explanatory. We import `kit` from the file we created before. Then, when the user clicks on the sign-in button, we call the `connect` function we created in our `stellar-wallets-kit.ts` file above. This will launch the built-in StellarWalletsKit modal, which allows the user to pick from the wallet options we configured (we configured all of them, with `allowAllModules`). We pass our own `setLoggedIn` function as the callback, which will be called in the `onWalletSelected` function in `stellar-wallets-kit.ts`. We end by updating the UI, based on whether the user is currently connected or not.
329
380
330
381
Now we can import the component in the frontmatter of `pages/index.astro`:
331
382
@@ -341,7 +392,7 @@ Now we can import the component in the frontmatter of `pages/index.astro`:
341
392
And add it right below the `<h1>`:
342
393
343
394
```diff title="pages/index.astro"
344
-
<h1>{greeting}</h1>
395
+
<h1>{greeting}</h1>
345
396
+<ConnectWallet />
346
397
```
347
398
@@ -366,19 +417,22 @@ Current value: <strong id="current-value" aria-live="polite">???</strong><br />
// Only use `innerHTML` with contract values you trust!
400
449
// Blindly using values from an untrusted contract opens your users to script injection attacks!
401
450
currentValue.innerHTML=result.toString();
402
451
} catch (e) {
403
452
console.error(e);
453
+
} finally {
454
+
button.disabled=false;
455
+
button.classList.remove("loading");
404
456
}
405
-
406
-
button.disabled=false;
407
-
button.classList.remove("loading");
408
457
});
409
458
</script>
410
459
```
411
460
412
461
This should be somewhat familiar by now. We have a `script` that, thanks to Astro's build system, can `import` modules directly. We use `document.querySelector` to find the elements defined above. And we add a `click` handler to the button, which calls `increment` and updates the value on the page. It also sets the button to `disabled` and adds a `loading` class while the call is in progress to prevent the user from clicking it again and visually communicate that something is happening. For people using screen readers, the loading state is communicated with the [visually-hidden](https://www.a11yproject.com/posts/how-to-hide-content/) span, which will be announced to them thanks to the `aria` tags we saw before.
413
462
414
-
The biggest difference from the call to `greeter.hello` is that this transaction gets executed in two steps. The initial call to `increment` constructs a Soroban transaction and then makes an RPC call to _simulate_ it. For read-only calls like `hello`, this is all you need, so you can get the `result` right away. For write calls like `increment`, you then need to `signAndSend` before the transaction actually gets included in the ledger.
463
+
The biggest difference from the call to `greeter.hello` is that this transaction gets executed in two steps. The initial call to `increment` constructs a Soroban transaction and then makes an RPC call to _simulate_ it. For read-only calls like `hello`, this is all you need, so you can get the `result` right away. For write calls like `increment`, you then need to `signAndSend` before the transaction actually gets included in the ledger. You also need to make sure you set a valid `publicKey` and a `signTransaction` method.
0 commit comments