Skip to main content

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:

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
If you haven't already installed the soroban-cli , you can do so by running the following command:
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 the epoch_interval and relayer
  • <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
...
tip

Please, save your deployed contract ID, you will need it to complete the challenge.

Please connect to Testnet network.

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 https://laboratory.stellar.org/#account-creator?network=futurenet, 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.

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.

connect

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]
tip

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! πŸŽ‰

connect

Remember, you must add Futurenet network lumens to your Freighter wallet to interact with the deployed example dapp. Visit https://laboratory.stellar.org/#account-creator?network=futurenet, 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!

Please connect to Testnet or Futurenet network.

info

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:

  1. Fork the challenge repository.
  2. Fill oracle/challenge/output.txt file with your wallet address. Filled file should look like:
Public Key: GBSXUXZSA2VEXN5VGOWE5ODAJLC575JCMWRJ4FFRDWSTRCJ123456789
  1. Create a Pull Request to the stellar/soroban-dapps-challenge/oracle branch. When the PR will be created, CI actions will check the oracle/challenge/output.txt file data and update your progress.
  2. Wait for the CI/CD pipeline results.
  3. 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.
  1. 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!