11 KiB
title: How to create a Token Factory with Ethereum — Part 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 we’ll create a Token Factory using Ethereum. In part 1 we’ll start by creating a DApp to interact with a single token, on part 2 we’ll 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 and Embark installed.
{% code_block copyBtn:true %} $ npm -g install embark {% endcode_block %}
Now, let’s 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:
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 let’s get started!
Adding the Token Contract
We’ll 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 Embark’s we see:
We haven't supplied any parameters to the contract and embark complains because the contract constructor takes a initial_balance parameter which we haven’t specified:
constructor(uint initial_balance) public {
_balances[msg.sender] = initial_balance;
_supply = initial_balance;
}
Let’s rectify this by specifying the initial_balance value in config/contracts.js
{% code_block copyBtn:true %} module.exports = { default: { // ..... gas: "auto", contracts: { 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 %}
Creating the UI
For the sake of brevity, we wouldn’t implement every single functionality in the contract. However, we’ll 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, we’ll edit app/index.html and add a simple form.
{% code_block copyBtn:true %}
<html> <head> </head>Query Balance
QueryAdding jQuery
To simplify the code a bit in this tutorial, we’ll 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
Let’s 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 %}
Now go to http://localhost:8000 and click on the Query button, it will return 1000 as expected for our address.
Transferring Tokens
Now let’s 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, let’s first add a simple form to the html page at app/index.html:
{% code_block copyBtn:true %}
<html> <head> </head>Welcome to Embark!
See the Wiki to see what you can do with Embark!
<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>
</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 %}
Let’s 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.
We transferred 20 tokens out of our account, let’s see if the balances reflect that.
You can even see in the Console a receipt of the transaction:
On to Part 2
In this tutorial we deployed and interacted with single Token. On part 2 we will adapt this DApp and create a true factory so new tokens can be dynamically deployed on the application side.