In this tutorial, you build your own Obscuro dApp from the start. This is an excellent way to experience a typical development process as you learn how Obscuro dApps are built, design concepts, tools and terminology.
In this tutorial, we’ll build a ‘Guessing Game’ dApp that provides an introduction to the fundamentals of Obscuro and shows you how to:
- Set up your local Ethereum development environment for Obscuro.
- Use Obscuro concepts to develop a dApp.
What is the Guessing Game?
The Guessing Game is an example of a dApp that can only be built on Obscuro, and not on native Ethereum.
You will build a dApp that demonstrates a basic Obscuro use case, a simple number guessing game. The dApp’s smart contract generates a random secret number, which is never revealed to anyone, including node operators, developers or end-user because of the privacy provided by Obscuro. The goal of the game is to guess this number, and each time an attempt is made, an entrance fee of 1 token is paid. If a user correctly guesses the number, the contract will pay out all of the accumulated entrance fees to them and reset itself with a new random number.
Without Obscuro, it would be possible to look up the internal state of the contract and cheat, and the game wouldn’t work.
The dApp has many of the features that you’d expect to find, including:
- Generating a random number known only to the dApp.
- Allow users to guess the numbers by depositing a token for each play.
- Colder/Warmer functionality to help guide users to the correct number.
- Events to alert users whether they have won or not.
- Track all player’s guesses.
- Contract owner privileges to start and stop the game.
Set up your environment
- You’ll need to install MetaMask following the instructions here
- Then download and run the Obscuro Wallet extension following the instructions here
- Now connect MetaMask to the Obscuro testnet following the instructions here
- Finally, check you can open the Remix IDE by visiting the following URL in your browser https://remix.ethereum.org
That’s it. You’re all set to start building your first dApp on Obscuro.
1. To begin, we’ll clone a template smart contract from Github through Remix by following these instructions
Click on GitHub
Paste “https://github.com/obscuronet/tutorial/blob/main/number-guessing-game/contracts/Guess.sol” into input
Select Guess.sol to open it in the editor, and we’re ready
Guess.sol is a Solidity file, and once we’re done, it will contain everything we need for the Guessing Game. Inside the file you’ll find the classic ERC-20 interface and a simple implementation named ERC20Basic representing OGG (Obscuro Guessing Game token). We’ll use OGG as a means of entry to play and to generate the prize pool.
There is also a skeleton contract called Guess inside Guess.sol, and this is what we’ll be extending. The contract Guess will be written the same as any other Solidity contract in Ethereum. It’ll run on the EVM and will exhibit the same behaviours.
Let’s start by defining the key variables we’ll need for the game. One is to store the secret number that only the contract knows about, and another containing the ERC-20 contract.
uint8 private _target IERC20 public erc20
Upon seeing this, you might think, hang on, I can see _target is set to private, but so what? Private variables in Ethereum don’t really mean they’re private, just that they can’t be accessed or modified by other smart contracts. And you’re right, that’s the case in Ethereum. But in Obscuro, private variables really are private (unless you explicitly decide to reveal them!). This is because all contracts and contract data is encrypted and only accessible within enclaves.
Our variables should now look like this
Next, let’s think about how we’ll instantiate this contract. We’ll need to:
- create an instance of the ERC-20 contract to manage and hold OGG tokens
- generate a secret random number
Let’s extend to the constructor to include these:
Now let’s write our function to generate the random number and secretly store it within the contract
This isn’t great as although the number is arguably random, it’s not random to anyone who knows how it’s generated and how to measure the inputs when the function is called. We are working on something better. Watch this space!
Okay, so right now, we should have the following:
- a constructor that initializes the contract
- a way to calculate the random number to be guessed
We now need to add the ability for a player to make an actual guess. But before we do that, we have not thought about the range we might want numbers to appear in. This would allow us to set the difficulty for any particular game. So let’s do that now.
Extend the constructor to accept a range int and create a variable for it, so we have something that looks like this
And we can change our random number function to adhere to the range by including the modulo operator %, like this:
Onto the actual guess! We’ll need the function to capture several things:
- Check the player has enough tokens to play
- Allow the player to transfer a token to the prize pool to pay for a guess
- Handle the player winning
- Handle the player not winning
Let’s go ahead and create a function called attempt that takes as input a guess
We already have the OGG tokens defined, so we can use this to check funds with
require(erc20.allowance(msg.sender, address(this)) >= 1 ether, "Check the token allowance.");
This assumes it costs 1 token per play.
Next, we transfer the funds for each play with something like
erc20.transferFrom(msg.sender, address(this), 1 ether);
Next, let’s add code that checks if the guess is correct or not. If the guess is correct, call the ERC-20 function to transfer all the funds in the contract and reset the game by calling _setNewTarget().
If it’s not correct, we do nothing. For example, your code might look something like this:
This works. You now have an Obscuro contract that will let players play the guessing game. But it’s not very good. So how do players know if they’ve won or not? We need events!
In Ethereum, events are typically written to the event log that is viewable by everyone. In Obscuro, events are viewable only to those they’re intended for. This is done by encrypting events with a key that is known only to the intended recipient. This is handled automatically for the recipient through the Wallet Extension.
So let’s go ahead and start adding in some events. First, we’ll need to emit events letting a player know after they’ve played whether they have won or not.
Events in Obscuro look exactly like events in any other EVM-based platform. All the complexity of ensuring privacy is abstracted away. So let’s go ahead and define two new events in our contract.
event Correct(address indexed player, uint8 guess, uint prize); event Incorrect(address indexed player, uint8 guess, uint prize);
Where prize represents the current prize pool so we can remind the player of what they’re playing for.
With these events in place, we can now call them accordingly within our attempt function, so we end up with something like this:
Before we move on, we’ve seen how we can keep things private (hint: all of the above is private!). What about if there are things we want to intentionally make public? For example, it makes sense for the current prize pool to be public, so let’s go ahead and explore that. It’s straightforward. All you do is create a public view that returns something - precisely the same as any other EVM contract!
Our function to return the prize pool is:
And that’s it! Congratulations on writing your first Obscuro smart contract!
You can now go ahead and deploy the contract following the instructions here
With that done, why not have a go at extending the contract to include warmer/colder functionality. Then, when a returning player plays again for the same again, if their new guess is closer to the previous guess, they’re told they’re warmer, and if it’s further, they’re colder.