Building a Token in Cipherem
In this guide, we will use Solidity within the Cipherem Protocol to mint a token, guided by the principles outlined in the Ethereum Token Specification.
Two Ways to Create Tokens:
1 - Use a token template:
- Go to Remix IDE.
- Use or build a token template at OpenZeppelin Wizard to create a token with all handlers and state already defined. This is the easiest way to create a token. You'll be able to customize those handlers and state after loading the template.
2 - Build from Scratch:
The following guide will guide you through the process of creating a token from scratch. This is a more advanced way to create a token, but it will give you a better understanding of how tokens work.
Preparations
Step 1: Initializing the Token
- Open Remix IDE and create a new file named MyToken.sol.
- Within MyToken.sol, initialize the token's state, defining its balance, name, ticker, and more:
local json = require('json')
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MyToken {
string public name = "My Token";
string public symbol = "MTK";
uint8 public decimals = 18;
uint256 public totalSupply = 1000000 * 10 ** uint256(decimals);
mapping(address => uint256) public balanceOf;
constructor() {
balanceOf[msg.sender] = totalSupply;
}
}
Let's break down what we've done here:
pragma solidity ^0.8.0;
: Specifies the Solidity compiler version.string public name = "My Token";
: Sets the token's name.string public symbol = "MTK";
: Sets the token's ticker symbol.uint8 public decimals = 18;
: Defines the number of decimals.uint256 public totalSupply = 1000000 * 10 ** uint256(decimals);
: Sets the total supply of tokens.mapping(address => uint256) public balanceOf;
: Creates a mapping to track balances.constructor() { balanceOf[msg.sender] = totalSupply; }
: Assigns the entire token supply to the contract creator.
Step 2: Transfer Function
Now let's add a function to handle token transfers.
function transfer(address _to, uint256 _value) public returns (bool success) {
require(_to != address(0), "Invalid address");
require(balanceOf[msg.sender] >= _value, "Insufficient balance");
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
event Transfer(address indexed _from, address indexed _to, uint256 _value);
This function checks the sender's balance and transfers tokens to the recipient if sufficient balance exists.
Step 3: Mint Function
Next, we'll add a function to mint new tokens.
function mint(uint256 _amount) public {
totalSupply += _amount;
balanceOf[msg.sender] += _amount;
emit Transfer(address(0), msg.sender, _amount);
}
This function allows the contract owner to mint new tokens, increasing the total supply.
Step 4: Approve and TransferFrom Functions
For more advanced token management, we'll add functions to allow approved transfers.
mapping(address => mapping(address => uint256)) public allowance;
function approve(address _spender, uint256 _value) public returns (bool success) {
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_to != address(0), "Invalid address");
require(balanceOf[_from] >= _value, "Insufficient balance");
require(allowance[_from][msg.sender] >= _value, "Allowance exceeded");
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
allowance[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
These functions allow users to approve others to spend tokens on their behalf.
Compile the contract
Move to the "Solidity Compiler" tab in the left navigator, select the correct compiler version as required by the pragma
directive in the contract, then compile:
Deploy the contract
Switch to the "Deploy & Run Transactions" tab, select "Injected Web3" as the environment to make Remix use your Metamask account as a signer.