Aion University

So you want to be a DApp developer?


Well you've come to the right place. You'll find comprehensive guides and documentation to help you start developing with Aion as quickly as possible, as well as support if you get stuck. Let's jump right in!

Let's DApp

πŸŽ“ Build a Decentralized App on Aion

Learn how to create a complete, decentralized application on the Aion Network.

Guide Level: Beginner

You are a developer who

  • Understands basic front-end knowledge(HTML, CSS, JavaScriptβ€Š-β€ŠThe application itself is written in React 15.6.1)
  • Is familiar with basic blockchain concepts
  • Is comfortable with smart contracts and how it works on blockchains
  • Solidity Language v0.4.15 (Optional - but you can read the docs here)

Overview

Learn to build a fun, decentralized application on the Aion Network. If you want to know more on how this demo dApp came to be, read the blog post!

Before we dive in, let's get a sneak peak of what you're going build! :hammer+:
Pet Roulette is a game of luck and it is built on top of the Aion Network.

The rules are:

  • 7 accounts choose an animal to win the round
  • Each account can place one bet per round
  • Bets must be within 1 and 100 AION

Try your luck & place your bets!! πŸ˜‰πŸ’ΈπŸ˜

Let's BUIDLπŸŽ“

1. Setup your Environment

Alright rockstars, we'll need a few things to set the stage 🎬

Requirements

1.1 Installation

We'll be cloning the tutorial starter Github Repo. In your command line, navigate to where you would like the project directory.

  1. Clone the Github Repo
  2. Navigate into the project directory
git clone https://github.com/aion-kimcodeashian/aion-roulette-tutorial.git
cd aion-roulette-tutorial
  1. Install webpack & http-server on your system
npm i --global webpack webpack-cli http-server
  • webpack - Bundles JavaScript files for usage in a browser.
  • http-server - A lightweight server that hosts your web app locally for development (localhost:8080)
  1. Install all the NPM dependencies for the project
npm install

You can see the dependencies installed in the package.json file. The important dependencies to note are:

  • React.js - JavaScript library for building user interfaces
  • aion-web3 - Aion's web3 API (application programming interface) on top of the Aion network

1.2 Project Structure

If you open up your project in your text editor, it should look like this

Demo dApp Project Structure

Demo dApp Project Structure

  • index.js - We'll be editing this file as it deals with all the client-side interactions of the dApp. We use React to render the DOM and make calls to interact with our smart contract
  • webpack.config.js - webpack file that bundles all of the React, JavaScript and CSS files into build.js
  • build.js - compiled JavaScript file that is injected in index.html
  • index.html - the webpage that serves the application
  • package.json β€Š- β€Šfile used to give information to NPM that allows it to identify the project and handle the project's dependencies

2. Write the Smart Contract

Here's where the magic of your application will happen. Let's write out smart contract!

Aion's FastVM currently only supports Solidity Language up to v0.4.15.

2.1 SafeMath

Practice Safe Math! :wink+:

What is it? SafeMath is a Solidity math library especially designed to support safe math operations. Safe means that it prevents overflow when working with uint.

  • using SafeMath for uint; - lets the contract know that we'll be using the SafeMath library for uint variables :1234+:

Open up the Casino.sol file (found in /contracts/Casino.sol). You should see the SafeMath library and an empty Casino contract.

pragma solidity 0.4.15;

library SafeMath {
  function mul(uint _a, uint _b) internal constant returns (uint c)
  { if (_a == 0) {
     return 0;
  }
    c = _a * _b;
    require(c / _a == _b);
    return c;
  }
  function div(uint _a, uint _b) internal constant returns (uint){
    require(_b > 0);
    return _a / _b;
  }
  function sub(uint _a, uint _b) internal constant returns (uint){
    require(_b <= _a);
    return _a - _b;
  }
  function add(uint _a, uint _b) internal constant returns (uint c){
    c = _a + _b;
    require(c >= _a);
    return c;
  }
}

contract Casino {
  using SafeMath for uint;
  
}

2.2 Basic Functionality

Let's lay down the basic functionalities of this contract.

contract Casino {
  using SafeMath for uint;
  address owner;
  
  // Constructor
  function Casino() public {
    owner = msg.sender;
  }
  
  // Make sure contract has balance > maximumBet so
  // distributePrizes() will be able to execute without failure
  function() public payable {}
  
  // refund all tokens back to owner
  function refund() public onlyOwner {
    uint totalBalance = this.balance;
    owner.transfer(totalBalance);
  }
  
  function kill() public {
    if(msg.sender == owner) selfdestruct(owner);
  }
}
  • Casino() - The constructor function. On deployment of the smart contract, it'll store the creator as owner of the smart contract. Which is stored in address public owner
  • payable() - Allows any AION amount send to be stored in the contract πŸ’Έ
  • kill()β€Š- Destroy the smart contract if there's any vulnerability or hack. It'll refund any remaining AION balance back to the owner πŸ’£

2.3 Variables

Now, let's create variables for the things we have to keep track of. Inline comments are provided to explain what each line is responsible for.

contract Casino {
  using SafeMath for uint;
  address owner;
  
  // The minimum bet a user has to make to participate in the game
  uint public minimumBet = 1; // Equal to 1.00 AION
  
  // The maximum bet a user has to make to participate in the game
  uint public maximumBet = 100; // Equal to 100 AION
  
  // The total number of bets the users have made
  uint public numberOfBets;
  
  // The maximum amount of bets can be made for each game
  uint public maxAmountOfBets = 7;
  
  // The total amount of AION bet for this current game
  uint public totalBet;
  
  // The total amount of AION paid out (contract paid out)
  uint public totalPaid;
  
  // The number / animal that won the last game
  uint public lastLuckyAnimal;
  
  // The current round number
  uint public numberRound;
  
  // Array of players in each round
  address[] public players;
  
  // Player object
  struct Player {
    uint amountBet;
    uint numberSelected;
  }
  
  // The address of the player and => the user info
  mapping(address => Player) public playerInfo;
  
  // Events that get logged in the blockchain
  event AnimalChosen(uint value);
  event WinnerTransfer(address to, uint value);
  
  // Modifier: Only allow the execution of functions when bets are completed
  modifier onEndGame(){
    if(numberOfBets >= maxAmountOfBets) _;
  }
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }
  
  function Casino() public {
    owner = msg.sender;
  }
  
  function() public payable {}
  
  function refund() public onlyOwner {
    uint totalBalance = this.balance;
    owner.transfer(totalBalance);
  }
  
  function kill() public {
    if(msg.sender == owner) selfdestruct(owner);
  }
}

These are all the variables we'll need to successfully track the game.

Events will be emitted on the blockchain when certain functions have executed (and can be read in the transaction receipts on the Dashboard). That way we can keep track of which Animal was chosen, and the winners' accounts and their winning portions. Read more about it under the How to Read Transactions section.

2.4 Functions

Let's recall the logic and functionality of the game:

  1. checkPlayerExists() - Only one account can place a bet per round
  2. bet() - Place a bet - pick an animal & bet amount (animals are mapped from 1-10)
  3. generateNumberWinner() - Generate random winning animal (random number)
  4. distributePrizes() - Identify & send AION to the winners' addresses
  • Add the following functions inside the Casino contract code.
  • Inline comments & descriptions are provided.

1. Check if account has already placed a bet

function checkPlayerExists(address player) public constant returns (bool){
    for(uint i = 0; i < players.length; i++){
       if(players[i] == player) return true;
    }
    return false;
  }

2. Player places a bet on an animal

  • Allow a player to place a bet
  • Stores the player address, the number they chose, AION amount betted
  • Updates relevant variables (player array, total betting pool, bets placed etc..)
function bet(uint numberSelected) payable {
  // Check that the max amount of bets hasn't been met yet
  require(numberOfBets <= maxAmountOfBets);
  
  // Check that the number to bet is within the range
  require(numberSelected >= 1 && numberSelected <= 10);
  
  // Check that the player doesn't exists
  require(checkPlayerExists(msg.sender) == false);
  
  // Check that the amount paid is bigger or equal the minimum bet
  require(msg.value >= minimumBet);
  	
  // Store player's address, bet amount, and animal chose
  playerInfo[msg.sender].amountBet = msg.value;
  playerInfo[msg.sender].numberSelected = numberSelected;
  	
  numberOfBets++; // Increase number of bets placed
  players.push(msg.sender); // Add player into array 
  totalBet += msg.value; // Increase total AION prize pool 
  
  // Check if the round is completed, if so - draw the winning animal 
  if(numberOfBets >= maxAmountOfBets) generateNumberWinner(); 
 }

3. Generate winning animal

  • We do this by generating a number from 1-10 that are mapped to the animals respectively

This is NOT a secure random number generator method.

function generateNumberWinner() private onEndGame {
  uint numberGenerated = block.number % 10 + 1; // This isn't secure
  lastLuckyAnimal = numberGenerated; // Store animal chosen
  distributePrizes(); // Call function to distribute prizes
}

4. Distribute AION to winners

  • Store winning players in an array
  • Proportion their winnings based on their bet amount (by dividing the winner bet pool)
  • Distribute AION to winner accounts found in the array we created
  • Reset/Update relevant variables (players, number, round, total bets, etc)
  function distributePrizes() private onEndGame {
    address[100] memory winners; // Create a temporary in memory array with fixed size
    uint count = 0;              // Winner count - how many winners
    uint winnerBetPool = 0;      // Total Winner Bet Pool - used to portion prize amount 

    // Store winners in array, and tally winner bet pool
    for(uint i = 0; i < players.length; i++){
      address playerAddress = players[i];
      if(playerInfo[playerAddress].numberSelected == lastLuckyAnimal){
        winners[count] = playerAddress;
        winnerBetPool += playerInfo[playerAddress].amountBet;
        count++;
      }
    }

    // If winning players, then distribute AION 
    if (count > 0){
      for(uint j = 0; j < count; j++){
        if(winners[j] != address(0)) {// Check that the address in this fixed array is not empty
        address playerAddressW = winners[j]; // Grab winning addresses
        uint winnerAIONAmount = SafeMath.div(SafeMath.mul(totalBet, playerInfo[playerAddressW].amountBet), winnerBetPool);
        winners[j].transfer(winnerAIONAmount); // Calculate winner proportions to the prize pool

        totalPaid += winnerAIONAmount; // Add to Total Payout
        WinnerTransfer(winners[j], winnerAIONAmount);
      }
      totalBet = 0; // Clear total bets, if no winner - totalBets get rolled over
    }
    
    players.length = 0; // Delete all the players array
    numberOfBets = 0;   // Reset number of bets
    numberRound++;      // Increase Round Number
  
}

DId you get lost?

Check out the final version of the smart contract on the Github Repo!

3. Deploy the Smart Contract

Now it's time to make sure our code compiles and deploys our smart contract deploys. We'll be using Titan Suite for this step.

Titan Suite is a one stop shop for all your smart contract needs. Whether you want to edit, compile, or deploy your contract onto the Aion Network, it can do it all! It's both an IDE and a CLI tool but for this purposeβ€Š - β€Šwe'll use the IDE.

What's great about the IDE is that it lints your contract for you. So, if your code isn't perfect or you missed a few things - β€Šit will tell you!

Requirements

Pssst... if you need testnet AION - check out the AION faucet!

If you're not familiar with Titan Suite, get comfortable with this guide here.

3.1 Compile

  1. Head over to Titan Suite's IDE and create a new file called Casino.sol and set the language to Solidity
  2. Copy & paste the finalized Casino.sol contract into the IDE
  3. Compile your contract - You will need to enter your Nodesmith API Endpoint as the Provider Address
  4. Once your contract has successfully compiled. Copy the ABI of the contract. You can do so by clicking the clipboard icon beside the 'Details' button. Go back into your text editor and paste the ABI in the Casino.json file. We'll be using the ABI to interact with our contract on the client-side of our application.

ABI - A list of the contract's functions and arguments (in JSON format). An account wishing to use a smart contract's function uses the ABI to hash the function definition so it can create the FastVM bytecode required to call the function.

3.2 Deployment

Deploy your contract in 3 easy steps!

  1. Navigate to the Accounts tab and create/import an account. You'll need to have some AION balance in order to deploy the contract.
  2. Go to the Run tab and fill in the necessary information (Provider Address, Account)
  3. In the dropdown list, select the Casino contract & click 'Deploy'

Deployment Successful?

Awesome! Remember to copy the contract address! We'll need it later to instantiate the contract on the client-side!

You can find it in the transaction receipt in the console portion of the IDE.

3.3 Deposit AION to Contract

Remember the payable() function we added to our smart contract? This function allows the contract to receive AION.

The winning payout logic and flow of the smart contract goes a little something like this.

When the last player successfully places their bet

  1. A winning animal is generated
  2. Winners are identified and payouts occur

This is executed inside of one transaction. Because of this, the contract balance is not updated until after the transaction has been sealed. Essentially, the contract would try to payout a balance it does not have (according to the blockchain), and thus the transaction would revert or fail.

To avoid this, we have to deposit the maximum bet amount (under the assumption that the last better placed a bet with the max amount), so that the contract already carries the balance in order to carry through the transaction.

You can do this by going to your AIWA (or whatever Aion wallet you use) and

  1. Send the maximum bet amount (in this case it's 100 AION)
  2. To your contract address

Now your contract is all locked & loaded! πŸ”«

Sending 100 AION to Contract Address

Sending 100 AION to Contract Address

4. Connect to Front End Application

Navigate back to your text editor and open up the index.js file (found in /src/js/index.js)

import React from 'react'
import ReactDOM from 'react-dom'
import Web3 from 'aion-web3'
import casinoJSON from './../../contracts/Casino.json' // import our contract JSON

// Initializing Variables
let web3;
let aiwa;
let aiwaInjected = false;
let myContract;
let contractAddress = "0xYourContractAddressHere";
let account = "Not Detected - Please download AIWA to play this game";

// On load, inject AIWA
window.onload = () => {

}

// Main React App
class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      lastLuckyAnimal: "",
      numberOfBets: 0,
      minimumBet: 0,
      maximumBet: 0,
      totalBet: 0,
      totalPaid: 0,
      maxAmountOfBets: 0,
      roundNumber: 0,
      accounts: account,
      doesPlayerExist: false,
    }
    this.updateState = this.updateState.bind(this)
  }

  componentDidMount() {
    console.log('componentDidMount');
    this.initializeContract();
  }

  initializeContract() {

  }

  // Update DOM from Contract information
  updateState() {
    console.log('updateState hit');

  }

  // Listen for user events and executes the voteNumber method
  setupListeners() {
    console.log('setupListeners hit');
    let liNodes = this.refs.numbers.querySelectorAll('li')

    liNodes.forEach(number => {
      number.addEventListener('click', event => {
        event.preventDefault();
        if (this.state.doesPlayerExist) { // If player exists, do not allow voting
          alert("This account has already placed a bet. Wait until next round!")
        } else {
          event.target.className = 'number-selected'
          console.log('number selected', event.target.value);
          this.voteNumber(event.target.value, done => {
            // Remove the other number selected
            for (let i = 0; i < liNodes.length; i++) {
              liNodes[i].className = ''
            }
          })
        }
      })
    })
  }

  // Send Number to Contract
  voteNumber(number, cb) {

  }

  render() {
    return (
    <div className="main-container">
      <h1>Welcome to Aion RouletteπŸš€</h1>
      <div className="rules">
        <div className="block">
          <b>Round #:</b> &nbsp;
          <span>{this.state.roundNumber}</span>
        </div>
        <div className="block ">
          <b>Number of Bets:</b> &nbsp;
          <span>{this.state.numberOfBets}</span>
          /
          <span>{this.state.maxAmountOfBets}</span>
        </div>
        <div className="block">
          <b>Last Winning Animal:</b> &nbsp;
          <span>{this.state.lastLuckyAnimal}</span>
        </div>
        <div className="block">
          <b>Total AION pool:</b> &nbsp;
          <span>{this.state.totalBet} AION</span>
        </div>
        <div className="block empty"></div>
        <div className="block">
          <b>Min Bet:</b> &nbsp;
          <span>{this.state.minimumBet} AION</span>
        </div>
        <div className="block">
          <b>Max Bet:</b> &nbsp;
          <span>{this.state.maximumBet} AION</span>
        </div>
        <div className="block">
          <b>Total AION paid out:</b> &nbsp;
          <span>{this.state.totalPaid} AION</span>
        </div>
      </div>

      <hr />
      <h2 className="link">
        When {this.state.maxAmountOfBets} bets have been placed - an animal will be randomly selected and a payout will occur.
        <br/>
        Winners who guessed correctly will split the amount in the AION pool!
        <br/>
        If no winner, total AION pool will rollover.
        <br/>
        See the smart contract in action <a href="https://mastery.aion.network/#/account/a0e51f852783e5edd470657e8e3581b091816c37aa783e7e52f3a4638d16349c" target="_blank">here!</a>
        <a href="https://twitter.com/KimCodeashian/status/1086077442026921984" target="_blank" className="info"> &#9432; </a>
      </h2>

      <hr />
      <div className="play">
        <h3>Let's Play!</h3>
        <p>
          <span>1. How much AION do you want to bet? <input className="bet-input" ref="aion-bet" type="number" placeholder="0"/> AION</span>
          <span>2. Now pick an animal!</span>
        </p>
        <ul ref="numbers" className="numbers">
          <li value="1"></li>
          <li value="2"></li>
          <li value="3"></li>
          <li value="4"></li>
          <li value="5"></li>
          <li value="6"></li>
          <li value="7"></li>
          <li value="8"></li>
          <li value="9"></li>
          <li value="10"></li>
        </ul>
      </div>

      <hr />
      <div className="footer">
        <div className="footer-content">
        <p><i>Only working with the Mastery Test Network πŸ“‘</i></p>
        <p><i>You can only vote once per account.</i></p>
        <p><i>Your account is: <strong>{this.state.accounts}</strong></i></p>
        <p><i>Your vote will be reflected when the next block is mined.</i></p>
        <p className="link"><i>Don't have AIWA? <a href="https://learn.aion.network/v1.0/docs/aiwa" target="_blank">Start here</a></i></p>
        <p className="link"><i>Need Testnet AION? <a href="https://faucets.blockxlabs.com/aion" target="_blank">Faucet</a></i></p>
        </div>
      </div>

      <div className="madeWithLove">
        <p>Made with πŸ”₯ by <a href="https://twitter.com/kimcodeashian" target="_blank">KimCodeashian</a> 🀘</p>
      </div>
    </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.querySelector('#root')
)

Basic structure:

  • Import necessary libraries, data (React, Reactdom, aion-web3, Casino.json)
  • Initialize global variables for AIWA, web3, contract instance, and contract address.
  • Enter your contract address in line 11
  • App constructor with state variables pre-defined, corresponding to the contract variables (we'll update these when we connect with the contract)
  • render() - Responsible for updating the DOM of our app. As our state (variables) updates, the application will update and the web browser will re-render accordingly

If you'd like to see the bare application before we fill in the code:

  1. In your terminal (in the project directory)
  2. Run the local server with this command http-server
  3. Go to http://localhost:8080/

Functions

We'll be filling out these necessary functions to get our dApp up and running! :runner+:

  1. window.onload() - Detect if the browser has AIWA
  2. initializeContract() - Intialize the Contract
  3. updateState() - Update the Application State
  4. voteNumber() - Allow users to place their bets

4.1 Detect for AIWA :eyes+:

What is AIWA? AIWA stands for Aion Wallet and it is pretty straightforward to use. If you're familiar with MetaMask, the developer experience is quite similar. A neat feature is that it will auto-inject a Web3 API connection to Aion.

When the browser loads, first thing we have to do is to check if the user has AIWA installed. Update the window.onload() function.

// On load, inject AIWA
window.onload = () => {
  if (aionweb3){
    aiwa = aionweb3;
    aiwaInjected = true
    console.log("βœ“ AIWA injected successfully");
  }
}

4.2 Initialize the Contract

This is where our handy ABI comes in πŸ˜‰! Remember, we imported it from our Casino.json file?

  • You'll need your Nodesmith API endpoint
  • If AIWA is not detected - we'll be using Nodesmith as our fallback connection. This way, the contract information can still be displayed! Although, If the user doesn't have AIWA, they will not be able to place bets 😒.
initializeContract() {
  
  if (!aiwaInjected) {
    // Fallback Nodesmith Connection
    web3 = new Web3(new Web3.providers.HttpProvider("https://api.nodesmith.io/v1/aion/testnet/jsonrpc?apiKey=ENTERYOURAPIKEYHERE"));

    // Contract Instance
    myContract = new web3.eth.Contract(casinoJSON.info.abiDefinition, contractAddress);
    console.log('Contract Instantiated:', myContract);
  
  } else {
    // Contract Instance w/ AIWA
    myContract = new aiwa.Contract(casinoJSON.info.abiDefinition, contractAddress);
    console.log('Contract Instantiated:', myContract);
  }
  
  this.updateState();     // Populate DOM w/ contract info
  this.setupListeners();
  setInterval(function(){ // Poll contract info every 5s
    this.updateState()
  }.bind(this), 5000)
}

4.3 Update the Application State

Now that we have initialized our contract, let's go ahead and:

  1. Update our state with the information stored in our contract (minimum bet, total pool, how many bets, etc)
  2. Check if AIWA is active. If so:
    • Update the page to reflect user's current Aion address
    • And do a quick check if the account has already placed a bet

All our contract calls are made using Aion Web3 API methods.

// Update DOM from Contract information
updateState() {
  console.log('updateState hit');
  
  if (aiwaInjected){ // update active account
    this.setState({
      accounts: aiwa.eth.accounts.toString(),
    })
    
    // Check if account has already placed a bet
    myContract.methods.checkPlayerExists(aiwa.eth.accounts.toString()).call({})
    .then(function(result){
      console.log('doesPlayerExist:', result);
      this.setState({
        doesPlayerExist: result
      })
    }.bind(this));
  }

  // Update minimum bet value
  myContract.methods.minimumBet().call({})
  .then(function(result){
    console.log('min bet:', result);
    this.setState({
      minimumBet: result
    })
  }.bind(this));

  // Update maximum bet value
  myContract.methods.maximumBet().call({})
  .then(function(result){
    console.log('min bet:', result);
    this.setState({
      maximumBet: result
    })
  }.bind(this));

  // Update total amount in bets
  myContract.methods.totalBet().call({})
  .then(function(result){
    console.log('total bet:', result);
    // Do the Division for 18 decimal points (AION), float 2 points
    let totalPool = (result / 1*Math.pow(10,-18)).toFixed(2);

    this.setState({
      totalBet: totalPool
    })
  }.bind(this));

  // Update AION amount paid out
  myContract.methods.totalPaid().call({})
  .then(function(result){
    console.log('total AION paid out:', result);
    // Do the Division for 18 decimal points (AION), float 2 points
    let totalPaidOut = (result / 1*Math.pow(10,-18)).toFixed(2);

    this.setState({
      totalPaid: totalPaidOut
    })
  }.bind(this));

  // Update numberOfBets
  myContract.methods.numberOfBets().call({})
  .then(function(result){
      console.log('number of bets:', result);
      this.setState({
        numberOfBets: result
      })
  }.bind(this));

  // Update maximum amount of bets
  myContract.methods.maxAmountOfBets().call({})
  .then(function(result){
      console.log('maxAmountOfBets:', result);
      this.setState({
        maxAmountOfBets: result
      })
  }.bind(this));

  // Update round number
  myContract.methods.numberRound().call({})
  .then(function(result){
      console.log('roundNumber:', result);
      let round = parseInt(result, 10) + 1;
      this.setState({
        roundNumber: round
      })
  }.bind(this));

  // Update last winner
  myContract.methods.lastLuckyAnimal().call({})
  .then(function(result){
    console.log('Last Lucky Animal:', result);
    let winner;
    
		// Map out numbers to animals
    switch(result) {
      case '1':
        winner = "Cow";
        break;
      case '2':
        winner = "Beaver";
        break;
      case '3':
        winner = "Penguin";
        break;
      case '4':
        winner = "Pig";
        break;
      case '5':
        winner = "Chick";
        break;
      case '6':
        winner = "Walrus";
        break;
      case '7':
        winner = "Cat";
        break;
      case '8':
        winner = "Monkey";
        break;
      case '9':
        winner = "Elephant";
        break;
      case '10':
        winner = "Lion";
        break;
      default:
        winner = "N/A";
    }

    this.setState({
      lastLuckyAnimal: winner
    })
  }.bind(this));
}

4.4 Place your Bets

Player Interaction Flow:

  1. Enter a number value for amount of AION to be betted
  2. Click on an animal to place the bet
    • Once clicked, AIWA should pop up and prompt the user to review the transaction and ask for sign off.
    • setupListeners() is the function that listens for this click event

voteNumber() Logic:

  • Checks if the bet amount is in between the minimum and maximum bet value
  • Initializes a transaction object (which encodes the bet() method in the smart contract, and relevant information that we'll need to send to the contract)
  • Prompts AIWA to allow the user to review and send the transaction.

Read more about web3's sendTransaction() method

// Send Number to Contract
voteNumber(number, cb) {
  
  let voteCallObject; // Initialize tx object
  let bet = (this.refs['aion-bet'].value).toString(); // Grab Aion Bet Amount
  console.log('bet =', bet);
  
  if (!aiwaInjected) { // Check AIWA is enabled
    alert("You will need to have AIWA enabled to place a vote");

  } else if (!bet || parseFloat(bet) < this.state.minimumBet) {
    alert('You must bet more than the minimum')
    cb()

  } else {
    // Create TX Object
    voteCallObject = {
      from: this.state.accounts,
      to: contractAddress,
      gas: 2000000,
      value: web3.utils.toNAmp(bet),
      data: myContract.methods.bet(number).encodeABI()
    }

    // Prompt AIWA
    aiwa.eth.sendTransaction(
      voteCallObject
    ).then(function(txHash){
      console.log('txHash:', txHash);
      if (window.confirm('Click "OK" to see transaction hash.')) {
        window.open(
          'https://mastery.aion.network/#/transaction/'+ txHash,
          '_blank' // <- This is what makes it open in a new window.
        );
      };
      cb()
    });
  }
}

Did you get lost?

See the completed version on the GitHub Repo

5. Run the Application!

Congrats! :fireworks+: You just finished coding up the front-end application! Now all you have to do is save your files & rebuild it.

Rebuild your application by running this command (in the main project directory /aion-roulette-tutorial)

npm run-script build

And - let's spin up the local server so you can see your application and smart contract in action!

http-server

Check it out on your localhost:8080

You should be able to see the full decentralized application YOU just built on Aion's testnet!!
It should look very similar to the 'real deal' 😜

6. How to Read Transactions

Alrighty β€Š- now that you've got your application up and running (and presumably you've played around with it). You should probably see some activity on the Aion Mastery Dashboard.

Check out the contract activity that is currently live with the Aion Pet Roulette dApp.

If you click on "Transaction Hash" :bookmark-tabs+: - you'll dive into a more detailed view of exactly what happens on the blockchain.

There are two types of contraction interactions:

  1. Bet Transaction - A player places a bet on an animal
  2. Payout Transaction - The last player of the round places a bet on an animal, which triggers the contract to generate a number from 1–10 and distribute prizes (all in 1 transaction)

Here are two screenshots that break down and translate what you see in the Transaction Details.

Events are what emits the Txn Logs (which we coded in the smart contracts). This is a great way to log what happens on the chain.

6.1 Bet Transaction

6.2 Payout Transaction

Need Help?

If you get stuck, try searching these docs πŸ‘† or head over to our Gitter channels or StackOverflow for answers to some common questions.

Written by Kimcodeashian :fire+:


πŸŽ“ Build a Decentralized App on Aion


Learn how to create a complete, decentralized application on the Aion Network.

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.