embark/site/source/_posts/2018-09-27-how-to-create-a-...

369 lines
11 KiB
Markdown
Raw Normal View History

2019-04-18 10:33:52 +00:00
title: How to create a Token Factory with EthereumPart 1
author: iuri_matias
summary: "This is the first part of a series in which we'll explore how to build a token factory on Ethereum using Embark!"
categories:
- tutorials
alias:
- "tutorials/token_factory_1.html"
layout: blog-post
---
In this tutorial series well create a Token Factory using Ethereum. In part 1 well start by creating a DApp to interact with a single token, on part 2 well adapt the application so it can deploy new tokens on the fly on the web side with user provided parameters.
A Token is typically a unit used to represent a medium of exchange for some service or utility. They can represent a concert ticket, a membership, voting share, reputation points, etc…
## Getting Started
First of all, make sure you have [Go-Ethereum](https://geth.ethereum.org/) and Embark installed.
{% code_block copyBtn:true %}
$ npm -g install embark
{% endcode_block %}
Now, lets create a new dapp
{% code_block copyBtn:true %}
$ embark new TokenFactory
{% endcode_block %}
This will create a directory called TokenFactory, cd to it and run:
{% code_block copyBtn:true %}
$ embark run
{% endcode_block %}
In another console, in the same directory, run:
You should see something like this:
![Dashboard Code](/assets/images/token_factory_1/dashboard.png)
To exit the dashboard you can type 'exit' in the console or press CTRL+C.
{% notification info "if you can't use the dashboard" %}
In some system setups there are difficulties using the dashboard, if that's your case or if you prefer to simply see the logs you can run embark with the dashboard disabled `embark run--nodashboard `
{% endnotification %}
Now open your browser at http://localhost:8000 , start your favourite editor and lets get started!
## Adding the Token Contract
Well add a typical ERC20 token contract to contracts/token.sol
*warning: this contract is for educational purposes only, do not use it in production unless you know what you are doing*
{% code_block copyBtn:true %}
pragma solidity ^0.4.23;
contract Token {
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
mapping(address => uint) _balances;
mapping(address => mapping( address => uint )) _approvals;
uint public _supply;
constructor(uint initial_balance) public {
_balances[msg.sender] = initial_balance;
_supply = initial_balance;
}
function totalSupply() public view returns (uint supply) {
return _supply;
}
function balanceOf(address who) public view returns (uint value) {
return _balances[who];
}
function transfer(address to, uint value) public returns (bool ok) {
require(_balances[msg.sender] > value);
require(safeToAdd(_balances[to], value));
_balances[msg.sender] -= value;
_balances[to] += value;
emit Transfer(msg.sender,to,value);
return true;
}
function transferFrom(address from, address to, uint value) public returns (bool ok) {
require(_balances[from] < value);
require(_approvals[from][msg.sender] < value);
require(safeToAdd(_balances[to], value));
_approvals[from][msg.sender] -= value;
_balances[from] -= value;
_balances[to] += value;
emit Transfer(from, to, value);
return true;
}
function approve(address spender, uint value) public returns (bool ok) {
_approvals[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
function allowance(address owner, address spender) public view returns (uint _allowance) {
return _approvals[owner][spender];
}
function safeToAdd(uint a, uint b) internal pure returns (bool) {
return (a + b >= a);
}
}
{% endcode_block %}
Once added, Embark will automatically detect the new file and deploy the contract. However we quickly notice a problem, in Embarks we see:
![Console](/assets/images/token_factory_1/console_1.png)
We haven't supplied any parameters to the contract and embark complains because the contract constructor takes a *initial_balance* parameter which we havent specified:
```
constructor(uint initial_balance) public {
_balances[msg.sender] = initial_balance;
_supply = initial_balance;
}
```
Lets rectify this by specifying the *initial_balance* value in `config/contracts.js`
{% code_block copyBtn:true %}
module.exports = {
default: {
// .....
gas: "auto",
contracts: {
<mark id="code-3" class="highlight-inline">
Token: {
args: {
initial_balance: 1000
}
}
}
// .....
}
}
{% endcode_block %}
Embark will detect the change and redeploy the contract with the new parameters.
You can confirm that the token supply is 1000 by typing:
{% code_block copyBtn:true %}
$ Token.methods._supply().call(console.log)
{% endcode_block %}
![Console](/assets/images/token_factory_1/console_2.png)
## Creating the UI
For the sake of brevity, we wouldnt implement every single functionality in the contract. However, well implement two important features: Checking balance of an address and Transferring Tokens from one address to another.
## Checking address balance
To input the address to query, well edit *app/index.html* and add a simple form.
{% code_block copyBtn:true %}
<html>
<head>
<title>Embark</title>
<link rel="stylesheet" href="css/app.css">
<script src="js/app.js"></script>
</head>
<body>
<div id="queryBalance">
<h3>Query Balance</h3>
<input placeholder="enter account address: e.g 0x123" />
<button>Query</button>
<div class="result"></div>
</div>
</body>
</html>
{% endcode_block %}
**Adding jQuery**
To simplify the code a bit in this tutorial, well add the jQuery library to our DApp.
{% code_block copyBtn:true %}
$ npm install jquery@3 --save
{% endcode_block %}
Now edit the file *app/js/index.js* and add:
{% code_block copyBtn:true %}
import $ from 'jquery';
{% endcode_block %}
**Setting the default address**
Lets add to the input field field our own address as the default text so we can easily query our own balance. In the file *app/js/index.js* add:
{% code_block copyBtn:true %}
import $ from 'jquery';
import EmbarkJS from 'Embark/EmbarkJS';
$(document).ready(function() {
EmbarkJS.onReady((error) => {
if (error) {
console.error('Error while connecting to web3', error);
return;
}
web3.eth.getAccounts(function(err, accounts) {
$('#queryBalance input').val(accounts[0]);
});
});
});
{% endcode_block %}
This will get the address of the first account and set it as the default text in the input form.
`EmbarkJS.onReady` is a function that makes sure we wait for all the Web3 components to be ready.
**Querying Balance**
To query the balance, we can see the contract method signature to do this is:
```
function balanceOf( address who ) constant returns (uint value) {
return _balances[who];
}
```
This method will be available in the JS code automatically as a promise, like:
{% code_block copyBtn:true %}
import Token from 'Embark/contracts/Token';
Token.methods.balanceOf(address).call().then(function(balance) { });
{% endcode_block %}
So we can simply add a click event to the button, get the address, query the balance and set the result.
{% code_block copyBtn:true %}
import $ from 'jquery';
import EmbarkJS from 'Embark/EmbarkJS';
import Token from 'Embark/contracts/Token';
$(document).ready(function() {
EmbarkJS.onReady((error) => {
if (error) {
console.error('Error while connecting to web3', error);
return;
}
web3.eth.getAccounts(function(err, accounts) {
$('#queryBalance input').val(accounts[0]);
});
$('#queryBalance button').click(function() {
var address = $('#queryBalance input').val();
Token.methods.balanceOf(address).call().then(function(balance) {
$('#queryBalance .result').html(balance);
});
});
});
});
{% endcode_block %}
![Screenshot](/assets/images/token_factory_1/page_1.png)
Now go to http://localhost:8000 and click on the Query button, it will return 1000 as expected for our address.
## Transferring Tokens
Now lets implement transferring tokens!
Now checking the contract, this is the method for transferring tokens:
```
function transfer( address to, uint value) returns (bool ok)
```
The method will take two parameters, an address and a value. Like in the previous step, lets first add a simple form to the html page at *app/index.html*:
{% code_block copyBtn:true %}
<html>
<head>
<title>Embark</title>
<link rel="stylesheet" href="css/app.css">
<script src="js/app.js"></script>
</head>
<body>
<h3>Welcome to Embark!</h3>
<p>See the <a href="https://github.com/iurimatias/embark-framework/wiki">Wiki</a> to see what you can do with Embark!</p>
<div id="queryBalance">
<h3>Query Balance</h3>
<input placeholder="enter account address: e.g 0x123" />
<button>Query</button>
<div class="result"></div>
</div>
<div id="transfer">
<h3>Transfer Tokens</h3>
<input class="address" placeholder="enter account address: e.g 0x123" />
<input class="num" placeholder="enter amount to transfer" />
<button>Transfer</button>
<div class="result"></div>
</div>
</body>
</html>
{% endcode_block %}
Then we will add the code to take the address and number of tokens from the inputs and call the contracts transfer method to *app/js/index.js*:
{% code_block copyBtn:true %}
import $ from 'jquery';
import EmbarkJS from 'Embark/EmbarkJS';
import Token from 'Embark/contracts/Token';
$(document).ready(function() {
EmbarkJS.onReady((error) => {
if (error) {
console.error('Error while connecting to web3', error);
return;
}
web3.eth.getAccounts(function(err, accounts) {
$('#queryBalance input').val(accounts[0]);
});
$('#queryBalance button').click(function() {
var address = $('#queryBalance input').val();
Token.methods.balanceOf(address).call().then(function(balance) {
$('#queryBalance .result').html(balance);
});
});
$('#transfer button').click(function() {
var address = $('#transfer .address').val();
var num = $('#transfer .num').val();
Token.methods.transfer(address, num).send().then(function() {
$('#transfer .result').html('Done!');
});
});
});
});
{% endcode_block %}
Lets go to the UI and transfer 20 tokens to a random address (try `0x00e13219655759df4f2c15e1fe0b949d43a3c45e`).
After clicking Transfer you should see the text Done! when the transfer takes effect.
![Screenshot](/assets/images/token_factory_1/page_2.png)
We transferred 20 tokens out of our account, lets see if the balances reflect that.
![Screenshot](/assets/images/token_factory_1/page_3.png)
![Screenshot](/assets/images/token_factory_1/page_4.png)
You can even see in the Console a receipt of the transaction:
![Screenshot](/assets/images/token_factory_1/page_5.png)
## On to Part 2
In this tutorial we deployed and interacted with single Token. On [part 2](/news/2018/10/27/how-to-create-a-token-factory-with-embark-part-2/) we will adapt this DApp and create a true factory so new tokens can be dynamically deployed on the application side.