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

[Guide] Deploy A Smart Contract via Web3

Overview

So you want to deploy a smart contract on Aion? You've come to the right place :raised-hands+: In this guide - we'll be going on a step by step journey on how to set up your environment, understand what it takes to deploy a smart contract, and how to interact with it.

You'll walk away knowing how to connect to Aion's Mastery Testnet, building and sending transactions, and the confidence to start building great things on the Aion Network.

Let me guess, you are:

  • A developer who's interested in learning blockchain, but don't know where to start
  • Experienced blockchain dev looking to learn how to write on Aion
  • A cool and curious cat who wants to learn how to deploy a contract

No matter who you are, we've worded this tutorial so that someone like you can have a seamless experience on getting started!

Setup

Alright rockstars, we'll need a few things to set the stage before we can deploy that smart contract!

Requirements

  • Node.js (recommended version: 10.x)
  • NPM (recommended version: 6.x)
  • A computer with an internet connection (Dial up works too)

Connect to the Aion Network

First we'll need to have access to an Aion Node. In this guide, we'll be using Nodesmith to connect to the Aion Network.

Nodesmith hosts Aion nodes so that you don't have to:

  • Host and manage the infrastructure of a full Aion node yourself

  • Wait over a day for the node to sync before you can begin interacting with the network

Let's get started:

  1. Sign Up and verify your e-mail
  2. Login to the developer portal with your account
  3. Once on Dashboard, create & nickname your new project. Bam! You've got your API Key. We'll be using this key to send requests to our Nodesmith endpoint.
  4. On "Select Network", and switch to the 'Testnet (Mastery)' option
Nodesmith Dashboard

Nodesmith Dashboard

Other ways to connect to the Aion Network

Aion Web3 Setup

Aion Web3 is an application programming interface that sits on top of the Aion Network. It allows you to interact with a local or remote Aion Node using an HTTP or IPC connection

We'll be using Web3 to

  • Create an Aion Account
  • Compile, Deploy, and Interact with our smart contract

Let's start by creating a directory, moving inside it, then installing Aion Web3 in there.

Run these commands in your terminal or command prompt:

# Create and move into our project folder
mkdir aion_smart_contract_demo
cd aion_smart_contract_demo

# Download & Install Aion Web3 
git clone https://github.com/aionnetwork/aion_web3
cd aion_web3
npm install

Easy peazy! Now that web3 is installed, let's go ahead and open the web3 console and connect to the Aion network by typing the command below.

:loudspeaker+: You'll need your Nodesmith endpoint for this step

node console.js <https://nodesmith-endpoint-url-here>

You should see something like this.

Successfully opened the console and connected to our Nodesmith endpoint

Successfully opened the console and connected to our Nodesmith endpoint

Create/Import an Account

Great! Now we'll be using Web3 to generate our very own Aion address.

Keep your private key safe!

  • It acts as your digital signature
  • Helps confirm that you, the holder of the account, approve transactions on the network
  • The network is designed to approve any transactions were public & private keys match

Need a wallet Interface?

Check out the easy to use in-browser wallet, AIWA. Once an account has been created, you can export the private key to deploy a contract using web3!

We need an Aion address so we can receive AION Coins - AION Coins - The native asset of the Aion blockchain. :money-with-wings+: in it. An account will allow you to sign transactions, deploy contracts and interact with DApps!

Now back to the Web3 console, run these commands to create an account.

// Create an account locally
let account = web3.eth.accounts.create(); 

// OR you can Import an account
let account = web3.eth.accounts.privateKeyToAccount('PasteYourPrivateKeyHere')

// Output details of our newly-created account
account;

Notes

  • web3.eth.accounts.create() generates an account and the private key

  • account: will display the details of the newly-created account. The output will resemble the structure shown below. Take note of the "address" field (lines 7-8) – this is your public Aion address. The "privateKey" field contains your private key.

{ _privateKey:
   <Buffer 61 1c 22 c0 c4 af 62 f7 2d a9 fe 1c 89 ba 81 19 1e 17 ff 00 8a d7 7c 0b b2 6e 52 f0 0b 96 2f d6 f7 ab 59 b5 bc aa 7c a6 d2 af 5a 72 cc 6a 88 6b e7 47 ... >,
  privateKey:
 '0xprivatekey123privatekey123privatekey123privatekey123privatekey123privatekey123privatekey123privatekey123privatekey123privatekey1',
  publicKey:
   <Buffer f7 ab 59 b5 bc aa 7c a6 d2 af 5a 72 cc 6a 88 6b e7 47 4a 42 6b fc 69 18 a1 33 fd 21 c4 1c db 1f>,
  address:
   '0xa01bc25b03d85eef6687ef95ccf614f41dda861d670612cae2c8ba5811a1bf46',
  signTransaction: [Function: signTransaction],
  sign: [Function: sign],
  encrypt: [Function: encrypt] }

Get AION in your Account

Alright let's get some AION in that account! :money-with-wings+:

We need AION to:

  • Deploy a contract
  • Interact with the contract
  • Send transactions
  1. Head over to the Faucet here
  2. Blockchain Network: Select Mastery
  3. Wallet: Paste your Aion Address
  4. Agree to Terms of Service and Privacy Policy
  5. Verify you're not a robot (so human beings, dogs, cats are cool)
  6. Press to pour! (Pretty self-explanatory)
  7. :fireworks+: 10 tokens wired to your given address, along with a transaction receipt that you can track search up on the Testnet Dashboard

Your account should now have 1 AION.

You can check the balance of your account by:

  • Aion Dashboard (Paste your account address into the search bar)
  • Through web3 with the following command
eth.getBalance(account.address).then(console.log);
1000000000000000000

Notes

  • Alternatively, you can use web3.utils.fromNAmp to to convert NAmp to AION

Smart Contract

Let's get the show on the road!

Smart Contracts 101

We write smart contracts in a programming language called Solidity - Solidity - Solidity is a contract-oriented programming language for writing smart contracts. It is used for implementing smart contracts on various blockchain platforms . If you haven't heard of it before, that's okay! You can read up all about it here.

Below you'll find a simple smart contract which we've named as Counter.sol. It acts as a counter that can be either increased or decreased. Comments are written in-line so you can get a better understanding of what's going on.

Create the Smart Contract File

  • Navigate in the project folder we made earlier (the aion_smart_contract_demo directory)
  • Create a new file and name it 'Counter.sol'
  • Paste the following code in and save :floppy-disk+:
/*
  sol Counter
  Simple Counter Contract - Increase / Decrease by 1
*/

pragma solidity ^0.4.10;

contract Counter {

  /* State Variables */
  // State variables are values which are permanently stored in contract storage.
  int private count; // = 0
  address owner;

  /* Events */
  event CounterIncreased(bool counter);
  event CounterDecreased(bool counter);

  /* Functions */
  // Functions are the executable units of code within a contract.
  function Counter() public {
    owner = msg.sender;
  }

  // Increase counter by 1
  function incrementCounter() public {
    count += 1;
    CounterIncreased(true);
  }
  
  // Decrease counter by 1
  function decrementCounter() public {
    count -= 1;
    CounterDecreased(true);
  }
  
  // Getter function that returns the current counter status
  function getCount() public constant returns (int) {
    return count;
  }
}

Compile

Before we deploy the smart contract, we’re going to need to compile our solidity code into an interface (ABI) and bytecode (bin).

Compile Smart Contracts for

  • Application Binary Interface (ABI): JavaScript Object that defines how the machine is to interact with the contract

  • Bytecode: Compiled ‘code’

Let's load the Solidity program into Web3 and compile our contract now :thumbsup+:
Enter each line into your Web3 console:

// Read the solidity program from file
let counterSol = fs.readFileSync("../Counter.sol", "utf8"); 

// Compile the contract
web3.eth.compileSolidity(counterSol).then((res) => compiled = res); 

// Display the compilation result
compiled; 

Notes

  • fs.readFileSync("./Counter.sol", "utf8"): Takes our Counter.sol contract, reads it then stores it in a variable we named counterSol

  • web3.eth.compileSolidity(counterSol): Lets web3 know that we want to compile this contract

  • compiled: Displays the output of the Solidity compiler (shown below). It contains the ABI Definition and VM bytecode, which we need to deploy to the network and interact with.

{ Counter:
   { code:
      '0x605060405234156100105760006000fd5b5b3360016000508282909180600101839055555050505b61002c565b6101858061003b6000396000f30060506040526000356c01000000000000000000000000900463ffffffff1680635b34b96614610049578063a87d942c1461005f578063f5c5ad831461008957610043565b60006000fd5b34156100555760006000fd5b61005d61009f565b005b341561006b5760006000fd5b6100736100f3565b6040518082815260100191505060405180910390f35b34156100955760006000fd5b61009d610105565b005b6001600060008282825054019250508190909055507f6816b015b746c8c8f573c271468a9bb4b1f0cb04ff12291673f7d2320a4901f76001604051808215151515815260100191505060405180910390a15b565b60006000600050549050610102565b90565b6001600060008282825054039250508190909055507f09a2ae7b00cae5ecb77463403c1d5d6c03cf6db222a78e22cbcafbe0a1ac9eec6001604051808215151515815260100191505060405180910390a15b5600a165627a7a72305820f68f8fcfd955a33bf1d1a62e3955a0c63f5618d3e8959171be1e7591bc53d4bd0029',
     info:
      { abiDefinition: [Array],
        languageVersion: '0',
        language: 'Solidity',
        compilerVersion: '0.4.15+commit.ecf81ee5.Linux.g++',
        source:
         '/*\n  sol Counter\n  Simple Counter Contract - Increase / Decrease by 1\n*/\n\npragma solidity ^0.4.10;\n\ncontract Counter {\n\n  /* State Variables */\n  // State variables are values which are permanently stored in contract storage.\n  int private count; // = 0\n  address owner;\n\n  /* Events */\n  event CounterIncreased(bool counter);\n  event CounterDecreased(bool counter);\n\n  /* Functions */\n  // Functions are the executable units of code within a contract.\n  function Counter() public {\n    owner = msg.sender;\n  }\n\n  // Increase counter by 1\n  function incrementCounter() public {\n    count += 1;\n    CounterIncreased(true);\n  }\n  \n  // Decrease counter by 1\n  function decrementCounter() public {\n    count -= 1;\n    CounterDecreased(true);\n  }\n  \n  // Getter function that returns the current counter status\n  function getCount() public constant returns (int) {\n    return count;\n  }\n}\n' 
      } 
   } 
}

Deploy

Awesome! Now that we've compiled our contract, it's time for deployment. By deploying a smart contract, we're sending a transaction to the network.

Your smart contract being deployed to Aion Network.

Your smart contract being deployed to Aion Network.

We'll be using Web3 to:

  • Build this transaction
  • Sign it on the client-side
  • Deploy the contract (by sending the signed transaction)

Building the Transaction

Before we even deploy the contract, we have to define the deployment transaction, and then sign it using our private key.

let contractInst = new eth.Contract(compiled.Counter.info.abiDefinition);

let deploy = contractInst.deploy( {data:compiled.Counter.code, arguments: []} ).encodeABI();

let deployTx = { gas: 4000000, gasPrice: 10000000000, data: deploy, from: account.address };

eth.accounts.signTransaction( deployTx, account.privateKey ).then( (res) => signedTx = res );

signedTx;

Notes

  • new eth.Contract(): Instantiates a new contract using the ABI definition we received from the compiler

  • contractInst.deploy().encodeABI(): Encodes the ABI of the contract's constructor; in this case, the constructor takes zero arguments, hence the arguments is a blank list

  • deployTx: Creates a transaction object with the encoded ABI

  • eth.accounts.signTransaction(): Signs the transaction using your account's private key

  • signedTx: Displays the signed transaction – the output's structure is shown in the snippet below.

{ 
  messageHash:
   '0xa14c3b0606610d6f27f3313f37d1a49eb743efe86783665af7024d0175ae94d7',
  signature:

 '0xf7ab59b5bcaa7ca6d2af5a72cc6a886be7474a426bfc6918a133fd21c41cdb1f63e13a4867162094dff943ce52b3bd550b59fca8480b084a5e8f4fd4c6d6efcdf568db315b0e7f977b175d39a96b73ea7df136d1ffcb43b4143c0ece8fc47407',
  rawTransaction:
   '0xf9023e008080b901c0605060405234156100105760006000fd5b5b3360016000508282909180600101839055555050505b61002c565b6101858061003b6000396000f30060506040526000356c01000000000000000000000000900463ffffffff1680635b34b96614610049578063a87d942c1461005f578063f5c5ad831461008957610043565b60006000fd5b34156100555760006000fd5b61005d61009f565b005b341561006b5760006000fd5b6100736100f3565b6040518082815260100191505060405180910390f35b34156100955760006000fd5b61009d610105565b005b6001600060008282825054019250508190909055507f6816b015b746c8c8f573c271468a9bb4b1f0cb04ff12291673f7d2320a4901f76001604051808215151515815260100191505060405180910390a15b565b60006000600050549050610102565b90565b6001600060008282825054039250508190909055507f09a2ae7b00cae5ecb77463403c1d5d6c03cf6db222a78e22cbcafbe0a1ac9eec6001604051808215151515815260100191505060405180910390a15b5600a165627a7a72305820f68f8fcfd955a33bf1d1a62e3955a0c63f5618d3e8959171be1e7591bc53d4bd002987057aa53e5f8850833d09008800000002540be40001b860f7ab59b5bcaa7ca6d2af5a72cc6a886be7474a426bfc6918a133fd21c41cdb1f63e13a4867162094dff943ce52b3bd550b59fca8480b084a5e8f4fd4c6d6efcdf568db315b0e7f977b175d39a96b73ea7df136d1ffcb43b4143c0ece8fc47407' 
}

Deploying the Contract

Up until now, we have not used any AION from our account since we haven't actually sent a transaction to the network. We only built the transaction in the last step.

Now let's send the transaction to the network.
Run this command into the Web3 console

web3.eth.sendSignedTransaction( signedTx.rawTransaction 
  ).on('receipt', receipt => { 
     console.log("Receipt received!\ntxHash =", receipt.transactionHash, 
                 "\ncontractAddress =", receipt.contractAddress);
  	 ctAddress = receipt.contractAddress;
});

Success! :tada+:
If everything goes as planned and contract deployment is a success , you should see the output below.

Receipt received! 
txHash = 0x83d4e490605437be85fed385a27889882f8f7bbd443a7b33b05a01d954e009cb 
contractAddress = 0xa0e5C73F2Aa1dbfD3bDc3cEb2D3BBEBCE467aeDf53D556e56A0eDe250f2B3d89

You can also see more details Aion Dashboard by pasting the transaction hash you received.

Confirmed Transaction Hash

Confirmed Transaction Hash

Interact

Now that we have our contract deployed on the network, we can interact with it. Like contract deployment, contract calls are transactions. The transaction object uses the same structure as before, but now we can populate the 'to:' field to point to the contract address (where our smart contract lives now).

Getter Function

In our Counter.sol contract, the getCount() function simply returns a constant. This means that it does not change or modify any values in the contract, but just outputs the value of a specific variable.

As long as you are only reading data from the blockchain and not changing the blockchain, you don't need to carry out a transaction. The function you call is carried out by the node and since nothing is mined, you do not need to pay any NRG.

So, since we're simply reading information from our contract, we can use web3.eth.call() without sending NRG - NRG - The internal pricing for running a transaction or contract on the Aion Network. Similary to how Gas is to Ethereum. or signing the transaction.

let txCall = {
	from: account.address, 
	to: ctAddress, 
	gas: 54321, 
        data: contractInst.methods.getCount().encodeABI()
};

web3.eth.call(txCall).then((res) => console.log(web3.utils.hexToNumber(res)));

Notes

  • txCall: Transaction object with getCount() method
  • web3.utils.hexToNumber(res): We take the return and convert it from hexadecimal to decimal format

As expected, it is zero - which is the initial value of the contract's count variable.

0

Function Calls

Let's try to use the incrementCounter() method, which modifies the state of the contract by increasing the counter by 1.

Since you are modifying the blockchain by sending instructions to the contract, this is a transaction. As with all transactions, it is necessary for the transaction to be signed and NRG to be required for execution.

Again, let's construct the transaction object and sign it - just like before.

// Create the transaction object
let txCallIncrement = {
    from: account.address, 
    to: ctAddress, 
    gas:54321, 
    data: contractInst.methods.incrementCounter().encodeABI()
};

// Sign it
web3.eth.accounts.signTransaction(
    txCallIncrement, account.privateKey
  ).then((res) => signedIncrementCall = res); 

// Output the signed transaction 
signedIncrementCall;

Notes

  • txCallIncrement: Transaction object with the incrementCounter() method
  • eth.accounts.signTransaction(): Signs the transaction using your account's private key
  • signedIncrementCall: Similarly to the code snippet for the contract deployment, the signed transaction has a rawTransaction
{ 
  messageHash:
   '0x6226521beacc1808ac93c4b9f18da4d34286bd3e1ecfda199c3593d4d19ee1ec',
  signature:
   '0xf7ab59b5bcaa7ca6d2af5a72cc6a886be7474a426bfc6918a133fd21c41cdb1f6db340a0d24ab5f0dd8f72bd189074d8734dba6edd88642bf5c8436df5a3278e92b446d5222335e13785657d34a1d6bbeb73438fc4568713700dea97f6a74f04',
  rawTransaction:
   '0xf89f02a0a0e5c73f2aa1dbfd3bdc3ceb2d3bbebce467aedf53d556e56a0ede250f2b3d8980845b34b96687057aa64e9c1d1882d4318800000002540be40001b860f7ab59b5bcaa7ca6d2af5a72cc6a886be7474a426bfc6918a133fd21c41cdb1f6db340a0d24ab5f0dd8f72bd189074d8734dba6edd88642bf5c8436df5a3278e92b446d5222335e13785657d34a1d6bbeb73438fc4568713700dea97f6a74f04' 
}

Waiting for Confirmation

Now, we're going to send the transaction and set up a handler as before, looking for the 'transactionHash' and 'receipt' event.

web3.eth.sendSignedTransaction(
    signedIncrementCall.rawTransaction
    ).on('transactionHash', txHash => { 
      console.log("txHash", txHash) }
    ).on('receipt',
      receipt => { console.log("receipt", receipt) }
    );

This means that the transaction hash and the receipt will be displayed when they are available from our Aion node.

You will notice that the transaction hash appears before the receipt does. Why is that?

Things to know

Transaction hashes are created as soon as the node receives the transaction

The receipt is available only after the node has processed the transaction - which may take up to 10 - 20 seconds on the Mastery TestNet.

The output on your console should look something like this.

txHash 0x911c71347ee575c9b0b0f6e29bd8545b355a31fc4621ebf05cc0d114327da4bd

receipt { blockHash:
   '0x98bfe8c010d74527795fca38d51053bcabe98401e5fe8f55a67bb6baa8b14be0',
  nrgPrice: '0x02540be400',
  logsBloom:
   '000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000
0000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000040000000000000000000000000000000000
',
  nrgUsed: '0x00aa7e',
  contractAddress: null,
  transactionIndex: 0,
  transactionHash:
   '0x911c71347ee575c9b0b0f6e29bd8545b355a31fc4621ebf05cc0d114327da4bd',
  gasLimit: '0x00d431',
  cumulativeNrgUsed: '0xaa7e',
  gasUsed: 43646,
  blockNumber: 971622,
  root:
   '04e198cf56e0e8b1b0a78d41f2ae0ddd9160276c387039a0c66f68f0ec46db44',
  cumulativeGasUsed: 43646,
  from:
   '0xa01bc25b03d85eef6687ef95ccf614f41dda861d670612cae2c8ba5811a1bf46',
  to:
   '0xa0e5c73f2aa1dbfd3bdc3ceb2d3bbebce467aedf53d556e56a0ede250f2b3d89',
  logs:
   [ { address:
        '0xa0e5C73F2Aa1dbfD3bDc3cEb2D3BBEBCE467aeDf53D556e56A0eDe250f2B3d89',
       logIndex: 0,
       data: '0x00000000000000000000000000000001',
       topics: [Array],
       blockNumber: 971622,
       transactionIndex: 0,
       id: null } ],
  gasPrice: '0x02540be400',
  status: true }

Alright, so everything looks good. :thumbsup+: We have our transaction hash and the receipt - so let's see if it actually updated!

Use web3.eth.call() to execute the getCount()method one more time.
We will use the same transaction object we created for it earlier (txCall).

web3.eth.call(txCall).then((res) => console.log(web3.utils.hexToNumber(res)));

Notes

  • txCall: Transaction object with getCount()method
  • web3.utils.hexToNumber(res): We take the return and convert it from hexadecimal to decimal format

Since we called the incrementCounter() method once, it is expected that the counter increased by 1.

1

Well there you have it! You can continue to increment/decrement this counter to your hearts content and get a good feel of things. After that, you're ready to start deploying more complex contracts and create awesome DApps on the Aion Network - and we cannot wait to see it!

Hey rockstar!

If you made it here that means only one thing - YOU just deployed a smart contract onto the Aion Network! :mortar-board+: :fireworks+: Congrats and give yourself a clap on the back. Feel free to explore other guides and never stop learning!

- Kimcodeashian :fire+:

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.