基于以太坊发布属于自己的数字货币(代币)完整版
Posted zhangbojiangfeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于以太坊发布属于自己的数字货币(代币)完整版相关的知识,希望对你有一定的参考价值。
https://blog.csdn.net/JAVA_HHHH/article/details/79771752
本文单纯从技术角度详细介绍如何基于以太坊ERC20创建代币的流程(此案例是部署的eth主网,非测试案例)
写在前面
本文所讲的代币是使用以太坊智能合约创建,阅读本文前,你应该对以太坊、智能合约有所了解,如果你还不了解,建议你先看以太坊是什么。
代币Token
如果不那么追求精确的定义,代币就是数字货币,比特币、以太币就是一个代币。
利用以太坊的智能合约可以轻松编写出属于自己的代币,代币可以代表任何可以交易的东西,如:积分、财产、证书等等。
因此不管是出于商业,还是学习很多人想创建一个自己的代币,先贴一个图看看创建的代币是什么样子。
以我自己发布的BliBli币 Bcoin为例
访问地址 : https://etherscan.io/token/0x73c8da697fe5e145f6269c4c852e59a7328f9371
今天我们就来详细讲一讲怎样创建一个这样的代币。
ERC20 Token
ERC20和代币一同出现, ERC20是以太坊定义的一个代币标准。是一种发行代币合约必须要遵守的协议,该协议规定了几个参数——发行货币的名称,简称,发行量,要支持的函数等,只有支持了该协议才会被以太坊所认同。
erc20标准代码如下
// https://github.com/ethereum/EIPs/issues/20
contract ERC20 {
function totalSupply() constant returns (uint totalSupply);
function balanceOf(address _owner) constant returns (uint balance);
function transfer(address _to, uint _value) returns (bool success);
function transferFrom(address _from, address _to, uint _value) returns (bool success);
function approve(address _spender, uint _value) returns (bool success);
function allowance(address _owner, address _spender) constant returns (uint remaining);
event Transfer(address indexed _from, address indexed _to, uint _value);
event Approval(address indexed _owner, address indexed _spender, uint _value);
}
totalSupply: 代表的是代币发行总量 totalSupply():该方法可以返回代币的总数量
name: 发行代币的名称 dicimals: 发行代币以后,代币交易的最小单位
balanceOf(): 该方法返回的是输入钱包地址后,该钱包的代币余额
tansferFrom() :从一个地址向另一个地址发送余额
approve(): 允许_spender从你的账户转出_value余额
allowance(): 允许_spender从你的账户转出_value的余额,调用多次会覆盖可用量。某些DEX功能需要此功能
event Transfer(): token转移完成后出发
event Approval(): approve(address _spender, uint256 _value)调用后触发
编写代币合约:
pragma solidity ^0.4.12;
contract IMigrationContract {
function migrate(address addr, uint256 nas) returns (bool success);
}
/* 灵感来自于NAS coin*/
contract SafeMath {
function safeAdd(uint256 x, uint256 y) internal returns(uint256) {
uint256 z = x + y;
assert((z >= x) && (z >= y));
return z;
}
function safeSubtract(uint256 x, uint256 y) internal returns(uint256) {
assert(x >= y);
uint256 z = x - y;
return z;
}
function safeMult(uint256 x, uint256 y) internal returns(uint256) {
uint256 z = x * y;
assert((x == 0)||(z/x == y));
return z;
}
}
contract Token {
uint256 public totalSupply;
function balanceOf(address _owner) constant returns (uint256 balance);
function transfer(address _to, uint256 _value) returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
function approve(address _spender, uint256 _value) returns (bool success);
function allowance(address _owner, address _spender) constant returns (uint256 remaining);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
/* ERC 20 token */
contract StandardToken is Token {
function transfer(address _to, uint256 _value) returns (bool success) {
if (balances[msg.sender] >= _value && _value > 0) {
balances[msg.sender] -= _value;
balances[_to] += _value;
Transfer(msg.sender, _to, _value);
return true;
} else {
return false;
}
}
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
balances[_to] += _value;
balances[_from] -= _value;
allowed[_from][msg.sender] -= _value;
Transfer(_from, _to, _value);
return true;
} else {
return false;
}
}
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner];
}
function approve(address _spender, uint256 _value) returns (bool success) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
}
contract BliBliToken is StandardToken, SafeMath {
// metadata
string public constant name = "BliBli";
string public constant symbol = "BCoin";
uint256 public constant decimals = 18;
string public version = "1.0";
// contracts
address public ethFundDeposit; // ETH存放地址
address public newContractAddr; // token更新地址
// crowdsale parameters
bool public isFunding; // 状态切换到true
uint256 public fundingStartBlock;
uint256 public fundingStopBlock;
uint256 public currentSupply; // 正在售卖中的tokens数量
uint256 public tokenRaised = 0; // 总的售卖数量token
uint256 public tokenMigrated = 0; // 总的已经交易的 token
uint256 public tokenExchangeRate = 625; // 625 BILIBILI 兑换 1 ETH
// events
event AllocateToken(address indexed _to, uint256 _value); // 分配的私有交易token;
event IssueToken(address indexed _to, uint256 _value); // 公开发行售卖的token;
event IncreaseSupply(uint256 _value);
event DecreaseSupply(uint256 _value);
event Migrate(address indexed _to, uint256 _value);
// 转换
function formatDecimals(uint256 _value) internal returns (uint256 ) {
return _value * 10 ** decimals;
}
// constructor
function BliBliToken(
address _ethFundDeposit,
uint256 _currentSupply)
{
ethFundDeposit = _ethFundDeposit;
isFunding = false; //通过控制预CrowdS ale状态
fundingStartBlock = 0;
fundingStopBlock = 0;
currentSupply = formatDecimals(_currentSupply);
totalSupply = formatDecimals(10000000);
balances[msg.sender] = totalSupply;
if(currentSupply > totalSupply) throw;
}
modifier isOwner() { require(msg.sender == ethFundDeposit); _; }
/// 设置token汇率
function setTokenExchangeRate(uint256 _tokenExchangeRate) isOwner external {
if (_tokenExchangeRate == 0) throw;
if (_tokenExchangeRate == tokenExchangeRate) throw;
tokenExchangeRate = _tokenExchangeRate;
}
/// @dev 超发token处理
function increaseSupply (uint256 _value) isOwner external {
uint256 value = formatDecimals(_value);
if (value + currentSupply > totalSupply) throw;
currentSupply = safeAdd(currentSupply, value);
IncreaseSupply(value);
}
/// @dev 被盗token处理
function decreaseSupply (uint256 _value) isOwner external {
uint256 value = formatDecimals(_value);
if (value + tokenRaised > currentSupply) throw;
currentSupply = safeSubtract(currentSupply, value);
DecreaseSupply(value);
}
/// 启动区块检测 异常的处理
function startFunding (uint256 _fundingStartBlock, uint256 _fundingStopBlock) isOwner external {
if (isFunding) throw;
if (_fundingStartBlock >= _fundingStopBlock) throw;
if (block.number >= _fundingStartBlock) throw;
fundingStartBlock = _fundingStartBlock;
fundingStopBlock = _fundingStopBlock;
isFunding = true;
}
/// 关闭区块异常处理
function stopFunding() isOwner external {
if (!isFunding) throw;
isFunding = false;
}
/// 开发了一个新的合同来接收token(或者更新token)
function setMigrateContract(address _newContractAddr) isOwner external {
if (_newContractAddr == newContractAddr) throw;
newContractAddr = _newContractAddr;
}
/// 设置新的所有者地址
function changeOwner(address _newFundDeposit) isOwner() external {
if (_newFundDeposit == address(0x0)) throw;
ethFundDeposit = _newFundDeposit;
}
///转移token到新的合约
function migrate() external {
if(isFunding) throw;
if(newContractAddr == address(0x0)) throw;
uint256 tokens = balances[msg.sender];
if (tokens == 0) throw;
balances[msg.sender] = 0;
tokenMigrated = safeAdd(tokenMigrated, tokens);
IMigrationContract newContract = IMigrationContract(newContractAddr);
if (!newContract.migrate(msg.sender, tokens)) throw;
Migrate(msg.sender, tokens); // log it
}
/// 转账ETH 到BILIBILI团队
function transferETH() isOwner external {
if (this.balance == 0) throw;
if (!ethFundDeposit.send(this.balance)) throw;
}
/// 将BILIBILI token分配到预处理地址。
function allocateToken (address _addr, uint256 _eth) isOwner external {
if (_eth == 0) throw;
if (_addr == address(0x0)) throw;
uint256 tokens = safeMult(formatDecimals(_eth), tokenExchangeRate);
if (tokens + tokenRaised > currentSupply) throw;
tokenRaised = safeAdd(tokenRaised, tokens);
balances[_addr] += tokens;
AllocateToken(_addr, tokens); // 记录token日志
}
/// 购买token
function () payable {
if (!isFunding) throw;
if (msg.value == 0) throw;
if (block.number < fundingStartBlock) throw;
if (block.number > fundingStopBlock) throw;
uint256 tokens = safeMult(msg.value, tokenExchangeRate);
if (tokens + tokenRaised > currentSupply) throw;
tokenRaised = safeAdd(tokenRaised, tokens);
balances[msg.sender] += tokens;
IssueToken(msg.sender, tokens); //记录日志
}
}
以上的代币合约,是参考以太坊已经ICO过,并且产生价值的代币合约参考而来,完整比且功能强大,此合约创建的代币,具有“交易”,“转账”,“异常检测”,“更改代币持有人”,“设置汇率”,“被盗处理”,“超发代币”等功能。
(解释下:在以太坊的世界中,硬通货就是ETH-以太币,相当于现实世界中的黄金,我们发布的代币,就相当于各国发行的需要 与黄金挂钩兑换比率的货币,国家对货币拥有控制权,只要合约功能进行扩展,创造代币的人也会对代币拥有控制权。)
(对于挖矿的误解:不少小哥哥小姐姐认为挖矿就是挖币,其实挖矿是挖区块,区块是干嘛的,是用来打包交易的,是存储数据的,代币是不用挖的,当你挖到了区块,代币是给你的奖励,在发行量一定的情况下,代币会越来越少,所以挖到区块的奖励会变少。那奖励少了为什么还要挖矿呢,因为你的任何一笔交易都需要记录,一个区块的大小也就几M,存储不了那么多交易信息,所以要持续挖区块来记录你的交易,同时交易的手续费,会奖励给挖出区块的人。)
部署合约:
部署合约有多种方式 1 geth 编译代码 ---部署合约
2 用ethereum wallet钱包部署合约
3 最简单直观的部署合约方式: MetaMask和Remix Solidity IDE 部署合约
我们按照 MetaMask和Remix Solidity IDE 来进行部署合约。
1: 创建钱包帐号。MetaMask是钱包的一种,在chrome浏览器中,安装MetaMask插件即可,安装完成后,右上角会出现一个“狐狸头”的标志,点击该标志,打开钱包,第一步,创建账户,(创建账户只需要输入面密码即可,名称创建后可以随便改,该账户就是一个hash值,如何给自己创建的账户冲以太币,可以上https://otcbtc.com/sign_up网站,按照操作买以太币,然后转账到自己创建的账户)创建成功后,记住密码还有产生的几个随机单词(一定要记录下来)。如下:
2:打开 Remix Solidity IDE 访问地址: http://remix.ethereum.org/#optimize=false&version=soljson-v0.4.21+commit.dfe3193c.js 界面如下
3: 拷贝“编写代币合约”后边的代码到Remix Solidity IDE中按照如下编译
4: create 发布 如下
5 create后,产生hash值,拷贝hash值,在钱包中添加token
OK,如上所示,第一个属于你的真正意义上的去中心化数字货币就诞生了。正式网络和测试网络部署方法一样,不需要买eth就是了。
如果是测试网络,如何获得ETH? 进入 https://gitter.im/kovan-testnet/faucet 下方直接发送你的账户地址(hash值)即可,一般五分钟到账,会得到五个测试网络用的ETH币。
6(如果部署的是eth主网,非测试网,执行该步骤,测试网络可以不理会)
发布了代币以后,如果以后进行ico,那么需要发布源码公开。步骤如下
① 拷贝部署成功的合约地址(hash),到 https://etherscan.io/ 右上角搜索hash
② 按照如下图进行verify AND publish
打开如下页面第一步
打开如下页面第二部
打开如下页面第三部
ok 现在的代币就比较完整了,差ico了
代币转账:
1 metamask钱包转账: 如下
输入地址和代币数量
2 网页钱包转账: 如下 https://www.myetherwallet.com/#send-transaction
登录账户:
转账交易
---------------------
作者:JAVA_HHHH
来源:CSDN
原文:https://blog.csdn.net/JAVA_HHHH/article/details/79771752
版权声明:本文为博主原创文章,转载请附上博文链接!
以上是关于基于以太坊发布属于自己的数字货币(代币)完整版的主要内容,如果未能解决你的问题,请参考以下文章