The Dapps Challenge is undergoing updates. Some functionality may not work for the time-being. Thank you for your patience as we work to make it available again soon!
This challenge will guide you through the process of building and shipping an oracle dapp on the Stellar network using Soroban. Oracle dapps (decentralized applications) provide the means for users to access real-world data and information from external sources and bring it on-chain.
In this challenge, you will learn how to deploy smart contracts to Futurenet, and how to interact with them through a web frontend. In this context, the term "ship" refers to finalizing the development process of your dapp, ensuring that it functions as expected, and is accessible for user interaction and testing through a hosted frontend. However, it's crucial to clarify that despite its functionality, the dapp is not promoted nor intended for deployment in a production-level setting on Mainnet. The challenge is designed for educational purposes only, helping you understand how a dapp can be built and interacted with, with further customization and development, it has the potential to evolve into a full-fledged, ready-to-use oracle solution.
Checkpoint 0: π¦ Install πβ
Start by installing the required dependencies.
Required:
stellar-cli
20.0.0-rc.4.1: Install Stellar CLINode
>=v18: Download NodeFreighter Wallet
: Freighter Wallet
First, clone the Soroban Dapps Challenge repo and check out the oracle
branch, which contains the code for the oracle smart contract that powers this dapp:
git clone https://github.com/stellar/soroban-dapps-challenge.git
cd soroban-dapps-challenge
git checkout oracle
cargo install --locked --version 20.0.0-rc.4.1 soroban-cli
Soroban CLI is the command line interface to Soroban. It allows you to build, deploy, and interact with smart contracts; configure identities; generate key pairs; manage networks; and more.
Checkpoint 1: π Setup the initialize.sh
Scriptβ
The initialize.sh
script is a shell script that will help you initialize the contracts and install dependencies. It is located in the top level directory.
The initialize.sh
script performs following actions:
- Creates a new wallet to serve as the token admin
- Funds token admin wallet with test tokens
- Builds and deploys contracts using this wallet
- Creates typescript bindings
- Installs dependencies
For this section, you'll need to configure parameters to initialize donation
and oracle
contracts.
You'll start with donation
contract:
-
First, Open
initialize.sh
: -
Find the following part at the end of the file:
echo "Initialize the DONATION contract"
- For the
--recipient
parameter, specify the wallet address that will be used to withdraw money from the donation contract. This may be your address.
initialize\
--recipient <YOUR_WALLET> \
Now for the oracle
contract:
- Find the following part of
initialize.sh
:
echo "Initialize the ORACLE contract"
- As you can see, there are several parameters that need to be specified here.
initialize \
--caller <OWNER_ADDRESS> \
--pair_name BTC_USDT \
--epoch_interval <TIME_IS_SECONDS> \
--relayer <RELAYER_ADDRESS>
Here is a description of each parameter:
<OWNER_ADDRESS>
- the address that will become the owner of the contract. This may be your address. Only the contract owner will be able to change theepoch_interval
andrelayer
<TIME_IS_SECONDS>
- frequency (in seconds) of price updates<RELAYER_ADDRESS>
- address of the wallet that will update the price (in the backend, in the CRON task). It is suggested to create a dedicated wallet for this (be sure to fund with test Lumens)
Checkpoint 2: π¬ Deploy Smart Contractsβ
Now that the initialization script is set up it's time to deploy the smart contracts to a Sandbox environment. Deploying a smart contract in a production setting involves submitting the contract code to the blockchain's main network ( Mainnet ), where it becomes part of the chain's immutable ledger. Deploying smart contracts to a Sandbox environment simulates that process without actually affecting Mainnet. When you deploy the smart contracts, you'll instead deploy to Futurenet, a test network with more cutting-edge features that have not yet been implemented in the Mainnet.
To build and deploy the contracts in a Sandbox environment, as well as to compile the TypeScript bindings, run the following command in your terminal:
npm run setup
Note: This command may require write privileges in some cases. If you encounter a "Permission denied" error when running this command, run the following command to grant write privileges to the
initialize.sh
script:chmod +x initialize.sh
If the command runs successfully, your terminal will return a series of messages notifying you about the successful initialization of the contracts and the post-installation sequence.
Deploy the BTC TOKEN contract
Contract deployed successfully with ID: CD5ZAJAPX5AAOB55G7SQEM63EQK5JRUZN2LUCDP66BRWV5HNGPDGJVDD
Deploy the DONATION contract
Contract deployed successfully with ID: CC7U75NM4FQQSPLCSX2FTUCAQ6VI6VBA5LDYSU3FRKXN3X2W3AL2SAJ3
Deploy the ORACLE contract
Contract deployed successfully with ID: CBK3VIRHK5QGHLKFTWHJI2ABMW2SATMIDPNQSCICCDRJU6DIFEWHLDD2
Initialize the BTC TOKEN contract
Done
Initialize the DONATION contract
Done
Initialize the ORACLE contract
Done
> [email protected] build-contracts
...
Please, save your deployed contract ID, you will need it to complete the challenge.
Checkpoint 3: β―οΈ Create a CRON taskβ
A CRON task is a scheduled operation performed at specified intervals, functioning as a customizable backend service. Here, you will run a CRON task to update the BTC price within the Oracle contract. Data can be fetched from an API and set to the contract using the set_price
function, in this case, the tutorial will use the CryptoPrice API. This is a free API that provides real-time cryptocurrency prices, and it is used in this tutorial for demonstration purposes only. You are free to use any price feed API of your choice.
The function that updates the price is already implemented in the cron-script.ts
file. To retrieve the data from the price feed, you will need to specify the following parameters:
- Secret key of wallet (relayer) that will fetch BTC price from API and set it to smart contract;
- Contract address of deployed Oracle Contract;
API_KEY
from https://api-ninjas.com/api/cryptoprice (for free).
Here is an example of a filled cron-script.ts
file:
const API_NINJA_KEY = "xSuoJa0icEhaQzk3IdomNWFmXK0qNG8lNZofYwJ4";
const sourceSecretKey =
"SBDLGM7RKXU6WYM2DRDIBULWAG7I6QDO3AONLERKWZPDDPQMMQ26F7TM";
const sourceKeypair = SorobanClient.Keypair.fromSecret(sourceSecretKey);
const sourcePublicKey = sourceKeypair.publicKey();
const contractId = "CBDRRNXD2UETJJL376B2VT3RS22YPF4NPWRDCMSBZAIQGWJIUM3U7552";
To run the CRON task, navigate to the cron
directory and run:
npm install
node cron-script.ts
Once the CRON task is running, it will fetch the BTC price from the API and set it to the contract every 15 minutes.
Here is an example of the output:
Running a task every 15 minutes
Current Time: 2023-11-08T00:30:00.036Z
lastEpochNr 0
deltaTimestamp 1699403400
Need to update the value
fetched priceData 3531576000
[updatePairPrice] View Transaction: https://futurenet.steexp.com/tx/5c68dd1eb6df7a926fa8fda3a3cd187d2855b74ceaa41469f69b33f81930c33a
[updatePairPrice] response.status: SUCCESS
value set!
You can specify the frequency of the CRON task by changing the cron.schedule
parameter in the cron-script.ts
file.
For example, to run the task every 5 minutes, change the parameter to:
cron.schedule("*/5 * * * *", async () => {
...
});
It's important to note that since the price feed is dependent on the CRON task, the price will not update until the CRON task has run at least once. Furthermore, the CRON task will need to keep running in order to keep the price feed updated. You can host the task on your localhost or on a server such as Vercel. For this example, the CRON task is hosted on a local host.
Checkpoint 4: π€ Connect the Frontend to the Backendβ
Now that you have the smart contracts deployed, and the cron job running, it's time to check out the frontend of your dapp.
From the top level directory run the following command to start the development server:
npm run dev
Now, open your browser and visit http://localhost:5173. You should be able to see the frontend of your dapp.
Note: Follow the instructions below and ensure that you have funded your wallet address that you intend to use from the browser.
Now that you have the frontend running, it's time to connect it with your smart contracts.
You will need to add some Futurenet network lumens to your wallet to interact with the dapp. Visit Stellar Lab, and follow the instructions to create and or fund an account on Futurenet.
Note: These are test lumens for use with Futurenet and cannot be used on Mainnet
Checkpoint 5: π§Ώ Oracle Insightsβ
Gaze into the crystal ball of APIs and retrive the price feed from the all connected internet. Data at your fingertips, at one time an abyss but pioneers have paved the way for many to cross. Here you will reach into the realm of off-chain data and pull out the price of BTC. In this section, you will mint tokens and deposit Bitcoin (BTC) into the donation contract. The conversion to USD will utilize the oracle price feed to ensure your donation is aligned with the current BTC to USD conversion rate.
- π¦ Mint Tokens
- π° Make a Donation
- Connect
- Mint
- Approve
- Check
Connect a Walletβ
Open the dapp frontend and click the "connect" and choose the wallet you want to use. For this example, you will use Freighter.
Mint USDC and BTCβ
Open the Mint BTC Tokens
tab, enter the desired token amount, and click the "Mint" button.
Approve Transactionβ
You should see a popup from Freighter asking you to sign the transactions. Click on "Approve" and wait for the transaction to be confirmed.
Check Updated Balanceβ
You should see an updated balance in the account balance component.
- Deposit
- Approve
- Check
Deposit into the Donation Contractβ
Open the frontend, enter the amount of BTC in USD that you would like to donate, then click the "Calculate" button. You should see the amount of BTC that you need to deposit in order to donate the specified amount in USD. For example, if you enter 35923.82 USD, you should see 1 BTC.
Approve Transactionβ
Click on "Approve" and wait for the transaction to be confirmed.
Check Updated Balanceβ
Once the transaction is confirmed, you should see the contract and your wallet balances update in the Donate
and Mint BTC Tokens
tabs, respectively.
Note: These are test tokens for use with Futurenet and cannot be used on Mainnet.
Checkpoint 6: π’ Ship it! πβ
In this step, you will deploy your dapp to a hosting platform so that it can be accessed by anyone with an internet connection. Note that it's on futurenet, the network used for testing, not mainnet for production use. You can use any hosting platform you like, but for demonstration purposes, this section will use Vercel. Vercel is a cloud platform for static sites and serverless functions that offers a free tier for developers. It also has a built-in integration with GitHub, which makes it easy to deploy your dapp directly from your GitHub repository.
If you don't already have a Vercel account, you will need to create one and link it to your GitHub account.
First install the Vercel cli:
npm i --global vercel
Then, remove any existing .vercel
directory in your project to ensure that you are starting with a clean slate:
rm -rf .vercel
Next, you will need to create a new project on vercel. To do this, run the following command:
vercel project add <PROJECT_NAME>
For example:
vercel project add oracle
Next you will pull in the project settings locally by running the following command:
vercel pull
Follow the answers to the prompts below to ensure that your local project is correctly linked to the target Vercel project:
? Set up β~/Documents/GitHub/test/soroban-dapps-challengeβ? [Y/n] y
? Which scope should contain your project? <VERCEL_UNAME>
? Link to existing project? [y/N] y
? Whatβs the name of your existing project? <PROJECT_NAME>
After following the prompts, you should see something similar to the following output:
...
π Linked to julian-dev28/oracle (created .vercel)
> Downloading `development` Environment Variables for Project oracle
β
Created .vercel/.env.development.local file [92ms]
> Downloading project settings
β
Downloaded project settings to ~/Documents/GitHub/test/soroban-dapps-challenge/.vercel/project.json [1ms]
Next, you will need to edit the settings
section in .vercel/project.json
to ensure that the installCommand
is set to npm i
:
"settings": {
"createdAt": 1699390700432,
"framework": null,
"devCommand": null,
- "installCommand": null,
+ "installCommand": "npm i",
"buildCommand": null,
"outputDirectory": null,
"rootDirectory": null,
"directoryListing": false,
"nodeVersion": "18.x"
}
Next, run the following command to build your dapp:
vercel build --prod
What does the vercel build
command do? It builds your dapp for production, which means that it optimizes your code for performance and creates an optimized production build of your dapp in the .vercel/output
directory. This is the directory that you will deploy to Vercel.
The output of the vercel build
command should look something like this:
$ vite build
..
dist/assets/index-91e5a562.js 490.69 kB β gzip: 139.50 kB
dist/assets/ModelViewer-fde23dd9.browser.esm-c08cdb2e.js 826.05 kB β gzip: 231.17 kB
dist/assets/index-46cc9288.js 3,107.82 kB β gzip: 888.20 kB
...
β built in 11.72s
β¨ Done in 12.14s.
β
Build Completed in .vercel/output [19s]
Next, you will deploy your dapp to Vercel by running the following command:
vercel deploy --prebuilt --prod
Using the --prebuilt
flag tells Vercel to deploy the build outputs in .vercel/output
that you created in the previous step.
Once the deployment is complete, you should see something similar to the following output:
π Inspect: https://vercel.com/julian-dev28/oracle2/Fk7RKb3H4RX1d1kBtHukgppRcv2m [9s]
β
Production: https://oracle2-3lrfgjzq9-julian-dev28.vercel.app [9s]
Please, save your production url, you will need it to complete the challenge.
You can now visit the preview link to see your deployed dapp! π
Remember, you must add Futurenet network lumens to your Freighter wallet to interact with the deployed example dapp. Visit Stellar Lab, and follow the instructions to create your Freighter account on Futurenet.
Checkpoint 7: πͺ Pass the Challenge!β
Now it's time to submit your work!
Submit your Production
URL from the previous step into the challenge form to pass the checkpoint!
Join our Community in Discord in case you have any issues or questions.
Checkpoint 8: β Check your work!β
In order to successfully complete this challenge, your work needs to be checked. Please, follow this steps:
- Fork the challenge repository.
- Fill
oracle/challenge/output.txt
file with your wallet address. Filled file should look like:
Public Key: GBSXUXZSA2VEXN5VGOWE5ODAJLC575JCMWRJ4FFRDWSTRCJ123456789
- Create a Pull Request to the
stellar/soroban-dapps-challenge/oracle
branch. When the PR will be created, CI actions will check theoracle/challenge/output.txt
file data and update your progress. - Wait for the CI/CD pipeline results.
- Fix errors if present:
- find the error reason in the Oracle challenge CI results (you can find a link right in the pull request);
- return to your forked repository;
- fix errors and commit changes. The existing PR will be checked again.
- If the pipeline was successful, then congratulations! You completed the challenge!π
Invite a friend to try out your dapp and ask them to provide feedback!
βοΈ Side Questsβ
πͺ¬ Add a new feature to your dapp (e.g. add a new price feed, add a new token, etc.)
π Extend your dapp's functionality by allowing users to query and interact with historic oracle data directly through the user interface.
π‘ Develop a function to respond to a significant BTC price change.
π User Workflows Checklistβ
During this exercise you should be able to:
- Clone the example repo (Oracle Dapp)
- Set the correct parameters in the
initialize.sh
script - Deploy your contract to Futurenet
- Deploy the example web ui somewhere (e.g. netlify, vercel, surge, etc.)
Then via the web UI, you should be able to:
- Connect your wallet
- See the BTC to USD conversion rate
- See your current balance
- See the contract balance
- Mint an asset
- Deposit an asset
- See your deposit(s) appear on the page as the transactions are confirmed
π‘οΈπ‘οΈ Take On More Challengesβ
View your progress and take on more challenges by visiting your User Dashboard!