Make your own template
Let’s make our own template! In this example template, we use SolidJS as the JavaScript framework, but other frameworks can be used with minor modifications. The template is using thehello-world example smart contract. As a part of the template initialization, bindings for the hello-world smart contract are created.
This example template is very simple, most of the work goes into creating the initialize.js file, which is used to take care of creating a user account, building and deploying the smart contract, and creating the smart contract TypeScript bindings.
1. Initialize a SolidJS project
Dependencies
Most of the needed dependencies are already included by the SolidJS template, we just need to add three more:dotenv package is needed for reading the environment variables, glob is used to find files in the project based on a pattern, and util contains a function that can be used to execute system commands asynchronously.
Smart contract
If you already have thehello-world smart contract, it can be used for the following steps. If not, run the stellar contract init heelo-world CLI command in you project root folder. Since we are going to interact with the smart contract from the initialize.js script, add the relative path to the smart contract in the .env file in the next step so the initialize.js script can find the contract files.
The root directory should look like this:
2. Environment variables
The SolidJS code itself doesn’t need environment variables for this simple example, but since we are going to add smart contract bindings, it makes sense to store information about the network and the user in an .env file instead of hard coding those values. These are the variables needed:alice with the Stellar CLI, creating a new account named alice will fail.
- initialize.js
The goal is to have a script that will handle everything smart contract-related, from creating a user account to deploying the smart contract and providing a TypeScript binding for easy smart contract calls from frontend code. The file initialize.js contains that script, and the functionality of it will be broken down in the following sections.
Definitions
Before diving into the functions in theinitialize.js script, a few constants and variables are defined. The most noteworthy here is execAsync(), which will let us execute CLI commands and wait for the command responses.
User
Now that we have the environment variables, dependencies and definitions taken care of, we can get into the scripts that handle the smart contract deployment and integration. First step towards the integration is to create a user:stellar keys generate, and funding it with Friendbot. The user’s name is fetched from the environment variables.
You can check the new user’s public key by running this CLI command:
Build contracts
We want the script to build the contract, or contracts in case there are more than one, and it’s a 2-step process. First, we clean up the target folder in case there’s a previous build, and then we call the CLI command to build the contract(s).removeFiles will delete any wasm or d files in the target directory.
Deploy contracts
Now that the smart contract has been built, we can deploy it to the network, so we can invoke the its functions from any client, such as our SolidJS template. There are three functions related to contract deployment. One that uses the Stellar CLI to deploy the Wasm to the network (deploy()), one that calls the deploy function for each Wasm found (deployAll()), in case there is more than one smart contract, and finally a helper function that gets the contract name by parsing the Wasm file name.
deploy() function will get the contract ID from the CLI call, and add the contract name, wasm file path, and contract ID to the smartContracts[] array.
In this example, we only use one smart contract, but it’s not uncommon to use multiple smart contracts in a dapp, so the template supports the use of multiple contracts.
Create bindings
The Stellar CLI has a convenient command to create an NPM package that makes it easy to call smart contract functions from a JavaScript/TypeScript-based frontend. We call the package “bindings” because that’s what it does: it binds the contract and the frontend together. As with the contract build functions, the binding function is also capable of handling multiple contracts, so there’s a function for creating the binding package for a contract (bind()) and a function that calls bind() for each contract (bindAll()).
bindAll() function iterates the smartContracts[] array. The reason for not just using the array of wasms, like in the deployAll() function, is that we need the contract ID to invoke the generated bindings functions on the network.
Import bindings
The last step is to configure the smart contract bindings client. TheimportContract() function creates a TypeScript file with a script that configures a client based on the smart contract ID, the network passphrase, and the RPC URL. The client makes it easy to make calls in the frontend code to the smart contract functions.
The file is stored with the contract name as the file name, and with the .ts as the extension, e.g., hello_world.ts.
Main function
At last, we have the main function, which calls the above functions in the right order. Note the asynchronous calls ofdeployAll() and bindAll(). The functions following them depend on the completion of the previous functions.
Complete initialize.js file
This is the complete file. Place it in the SolidJS root:4. Modify Vite config
SolidJS is using the build tool Vite, and we need to make a minor addition to the Vite configuration file (vite.config.ts) for the module exports to work. Add these lines to the config:
5. Build the frontend
The template is now ready to use the smart contract and its binding through the client. Let’s build a very simple dapp, a frontend for the Hello World smart contract, with a text input field and a send button. When a user enters a text string in the input field and clicks the send button, the contract function is invoked with the text string as the argument. The returned value, a string array, is displayed in the frontend. Here’s an example of how the code could look the existing code in thesrc/App.tsx file with this code:
6. Try it out
We can now run the code with this command:http://localhost:3000 unless the port 3000 is already in use.