一.ERC20代币合约与web3调用

  • ERC20代币合约在小白看来觉得很高大上,但其实就是一个代币的定义标准,方便其他dapp统一调用各种代币的方法。如图:

二.ERC20合约标准

官方链接

contract ERC20 {
//**********9个函数*******
//1.代币的名字,如:"黑马币"
function name() constant public returns (string name);
//2.代币的简称,例如:HMB
function symbol() public constant returns (string symbol);
//3.代币的最小分割量 token使用的小数点后几位。比如如果设置为3,就是支持0.001表示
function decimals() public constant returns (uint8 decimals);
//4.token的总量
function totalSupply() public constant returns (uint totalSupply); //5.余额 返回某个地址(账户)的账户余额
function balanceOf(address _owner) public constant returns (uint balance); /*6.转账 交易代币 从消息发送者账户中往_to账户转数量为_value的token,
从代币合约的调用者地址上转移 _value的数量token到的地址 _to
【注意:并且必须触发Transfer事件】*/
function transfer(address _to, uint _value) public returns (bool success); /*7.两个地址转账
从账户_from中往账户_to转数量为_value的token,与approve方法配合使用
从地址 _from发送数量为 _value的token到地址 _to
【注意:并且必须触发Transfer事件】
transferFrom方法用于允许合约代理某人转移token。条件是from账户必须经过了approve。*/
function transferFrom(address _from, address _to, uint _value) public returns (bool success); //8.批准_spender能从合约调用账户中转出数量为_value的token
function approve(address _spender, uint _value) public returns (bool success);
//9.获取_spender可以从账户_owner中转出token的剩余数量
function allowance(address _owner, address _spender) public constant returns (uint remaining); //**********2个事件*******
//1.发生转账时必须要触发的事件,transfer 和 transferFrom 成功执行时必须触发的事件
event Transfer(address indexed _from, address indexed _to, uint _value);
//2.当函数 approve(address _spender, uint256 _value)成功执行时必须触发的事件
event Approval(address indexed _owner, address indexed _spender, uint _value);
}

三.ERC20代币合约实现

// 此合约实现不记得是哪看到后复制保存的......和官网案例类似
pragma solidity ^0.4.25; interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; } contract TokenERC20 {
string public name; // ERC20标准
string public symbol; // ERC20标准
uint8 public decimals = 2; // ERC20标准,decimals 可以有的小数点个数,最小的代币单位。18 是建议的默认值
uint256 public totalSupply; // ERC20标准 总供应量 // 用mapping保存每个地址对应的余额 ERC20标准
mapping (address => uint256) public balanceOf;
// 存储对账号的控制 ERC20标准
mapping (address => mapping (address => uint256)) public allowance; // 事件,用来通知客户端交易发生 ERC20标准
event Transfer(address indexed from, address indexed to, uint256 value); // 事件,用来通知客户端代币被消费 ERC20标准
event Burn(address indexed from, uint256 value); /**
* 初始化构造
*/
function TokenERC20(uint256 initialSupply, string tokenName, string tokenSymbol) public {
totalSupply = initialSupply * 10 ** uint256(decimals); // 供应的份额,份额跟最小的代币单位有关,份额 = 币数 * 10 ** decimals。
balanceOf[msg.sender] = totalSupply; // 创建者拥有所有的代币
name = tokenName; // 代币名称
symbol = tokenSymbol; // 代币符号
} /**
* 代币交易转移的内部实现
*/
function _transfer(address _from, address _to, uint _value) internal {
// 确保目标地址不为0x0,因为0x0地址代表销毁
require(_to != 0x0);
// 检查发送者余额
require(balanceOf[_from] >= _value);
// 确保转移为正数个
require(balanceOf[_to] + _value > balanceOf[_to]); // 以下用来检查交易,
uint previousBalances = balanceOf[_from] + balanceOf[_to];
// Subtract from the sender
balanceOf[_from] -= _value;
// Add the same to the recipient
balanceOf[_to] += _value;
Transfer(_from, _to, _value); // 用assert来检查代码逻辑。
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
} /**
* 代币交易转移
* 从自己(创建交易者)账号发送`_value`个代币到 `_to`账号
* ERC20标准
* @param _to 接收者地址
* @param _value 转移数额
*/
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
} /**
* 账号之间代币交易转移
* ERC20标准
* @param _from 发送者地址
* @param _to 接收者地址
* @param _value 转移数额
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= allowance[_from][msg.sender]); // Check allowance
allowance[_from][msg.sender] -= _value;
_transfer(_from, _to, _value);
return true;
} /**
* 设置某个地址(合约)可以创建交易者名义花费的代币数。
*
* 允许发送者`_spender` 花费不多于 `_value` 个代币
* ERC20标准
* @param _spender The address authorized to spend
* @param _value the max amount they can spend
*/
function approve(address _spender, uint256 _value) public
returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
} /**
* 设置允许一个地址(合约)以我(创建交易者)的名义可最多花费的代币数。
*-非ERC20标准
* @param _spender 被授权的地址(合约)
* @param _value 最大可花费代币数
* @param _extraData 发送给合约的附加数据
*/
function approveAndCall(address _spender, uint256 _value, bytes _extraData)
public
returns (bool success) {
tokenRecipient spender = tokenRecipient(_spender);
if (approve(_spender, _value)) {
// 通知合约
spender.receiveApproval(msg.sender, _value, this, _extraData);
return true;
}
} /**
* 销毁我(创建交易者)账户中指定个代币
*-非ERC20标准
*/
function burn(uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value); // Check if the sender has enough
balanceOf[msg.sender] -= _value; // Subtract from the sender
totalSupply -= _value; // Updates totalSupply
Burn(msg.sender, _value);
return true;
} /**
* 销毁用户账户中指定个代币
*-非ERC20标准
* Remove `_value` tokens from the system irreversibly on behalf of `_from`.
*
* @param _from the address of the sender
* @param _value the amount of money to burn
*/
function burnFrom(address _from, uint256 _value) public returns (bool success) {
require(balanceOf[_from] >= _value); // Check if the targeted balance is enough
require(_value <= allowance[_from][msg.sender]); // Check allowance
balanceOf[_from] -= _value; // Subtract from the targeted balance
allowance[_from][msg.sender] -= _value; // Subtract from the sender's allowance
totalSupply -= _value; // Update totalSupply
Burn(_from, _value);
return true;
}
}

四.ERC20代币合约编译

const solc = require('solc');
const path = require('path');
const fs = require('fs'); //1.1 合约代码文件路径
const sourceFilePath = path.resolve(__dirname,'./TokenERC20.sol');
//1.2 合约编译后的文件路径
const bytecodeFilePath = path.resolve(__dirname,'./TokenERC20.bytecode');
//2.读取文件
const source = fs.readFileSync(sourceFilePath,'utf-8');
//3.编译
const result = solc.compile(source,1);
//console.log(result); console.log('1.编译完成:'+sourceFilePath); fs.writeFileSync(bytecodeFilePath,JSON.stringify(result.contracts[':TokenERC20']),'utf-8');
console.log('2.字节文件写入完成:'+bytecodeFilePath); //4.暴露给外部访问
//module.exports=result.contracts[':TokenERC20'];

五.web3调用

//1.1 导入 编译好的 合约的 字节代码 和 abi
const path = require('path');
const fs = require('fs');
//1.2 合约编译后的文件路径
const bytecodeFilePath = path.resolve(__dirname,'./TokenERC20.bytecode');
const bytecodeJsonStr = fs.readFileSync(bytecodeFilePath,'utf-8');
const byteCodeJsonObj = JSON.parse(bytecodeJsonStr);
//const {bytecode,interface} = require('./compilCaiPiao');
const bytecode = byteCodeJsonObj.bytecode;
const interface = byteCodeJsonObj.interface; //2.导入 hd钱包provider
const HDWalletProvider = require("truffle-hdwallet-provider");
//3.助记词(相当于是我们的私钥)
const mnemonic = "jar ... cat beef"; // 12 word mnemonic
//4.创建 provider,可以用来访问 以太坊真实网络节点
const provider = new HDWalletProvider(mnemonic, "https://rinkeby.infura.io/v3/3a60f2b160....",1);//最后的0 是获取 助记词 的第1个地址 //5.创建web对象
const Web3 = require('web3');
const web3= new Web3(provider); async function main(){
console.log('开始与以太网交互......');
const usrAdr = await web3.eth.getAccounts();//0x6c57CD10B4384C605aC748937b6cC1dF6C8eddA9
web3.eth.defaultAccount = usrAdr[0];
console.log('当前调用者的地址:' + web3.eth.defaultAccount); //6.部署合约到 以太网节点
//let contractObj =await deployContract(); //7.调用合约
//7.0 创建 远程智能合约
const contractObj = await new web3.eth.Contract(JSON.parse(interface),'0x46495b091cd3Fcb789cC336c3B5e9041E28555b0');
console.log('获取【合约】对象成功!'); // // 7.1 获取指定地址余额
await getBalanceAt(contractObj,'0x85BCc0F34718e80c332d41C513B72f8640B05249');
//await transferTo(contractObj,'0x83E9e99B7f5018680930baE0C7801555C850D9C5',10000000);
//await approveTo(contractObj,'0x83E9e99B7f5018680930baE0C7801555C850D9C5',1000000000);
await allowanceAt(contractObj,'0x85BCc0F34718e80c332d41C513B72f8640B05249','0x83E9e99B7f5018680930baE0C7801555C850D9C5');
await transferFrom(contractObj,'0x85BCc0F34718e80c332d41C513B72f8640B05249','0x737Df786f6e86625258960970c6752Fd7926F752',1);
await allowanceAt(contractObj,'0x85BCc0F34718e80c332d41C513B72f8640B05249','0x83E9e99B7f5018680930baE0C7801555C850D9C5');
//await getBalanceAt(contractObj,'0x737Df786f6e86625258960970c6752Fd7926F752');
// //7.2 显示合约账户余额
// await showContracMoney(contractObj);
// //查看调用者购买的号码
// await showInvokerLuckNum(contractObj); // 7.3 开奖+
// await withdrawLottery(contractObj); // 7.4 显示买家账户列表
// await showUsrList(contractObj);
// await showContracMoney(contractObj);
// 7.5 重置数据
//await resetContract(contractObj);
//await showManageAddress(contractObj);
//await killContract(contractObj); console.log('结束!'); } //启动
main(); // 1.部署合约
async function deployContract() {
console.log('开始部署合约......');
let contractObj = await new web3.eth.Contract(JSON.parse(interface))
.deploy({
data: bytecode,//TokenERC20(uint256 initialSupply, string tokenName, string tokenSymbol)
arguments: ['1000000000','梦想零钱','DreamCoin']
}).send({
from:web3.eth.defaultAccount,
gas:'1000000'
}); console.log('部署成功,合约地址:【'+contractObj.options.address+'】');
return contractObj;
} // 2.查询余额
async function getBalanceAt(contractObj,usrAdr) {
let usrMoney = await contractObj.methods.balanceOf(usrAdr).call();
console.log('地址【'+usrAdr+'】余额:'+usrMoney);
} //3.将当前调用者的钱 转 money 金额给 usrAdrTo
async function transferTo(contractObj,usrAdrTo, money) {
let result = await contractObj.methods.transfer(usrAdrTo,money).send({
from:web3.eth.defaultAccount,
gas:'1000000'
});
console.log('【'+web3.eth.defaultAccount+'】向【'+usrAdrTo+'】转账【'+money+'】完毕');
console.log('转账完毕~记录如下:')
console.log(result);
} //4.授权(当前调用者授权给 spenderAdr 操作数额为 money 的代币)
async function approveTo(contractObj,spenderAdr, money){
let result = await contractObj.methods.approve(spenderAdr,money).send({
from:web3.eth.defaultAccount,
gas:'1000000'
});
console.log('【'+web3.eth.defaultAccount+'】向【'+spenderAdr+'】授权【'+money+'】完毕!');
//console.log(result);
} //5.查询授权
async function allowanceAt(contractObj,ownerAdr,spenderAdr) {
let result = await contractObj.methods.allowance(ownerAdr,spenderAdr).call();
console.log('查询:【'+ownerAdr+'】给【'+spenderAdr+'】剩余授权余额为:'+result);
} //6.转账(汇款人地址,收款人地址,金额)
async function transferFrom(contractObj,usrAdrFrom, usrAdrTo, money) {
let result = await contractObj.methods.transferFrom(usrAdrFrom,usrAdrTo,money).send({
from:web3.eth.defaultAccount,
gas:'1000000'
});
console.log('【'+usrAdrFrom+'】向【'+usrAdrTo+'】转账【'+money+'】完毕');
//console.log(result);
}

以太坊ERC20代币合约案例的更多相关文章

  1. 以太坊ERC20代币开发

    以太坊ERC20代币开发首先需要对以太坊,代币,ERC20,智能合约等以太坊代币开发中的基本概念有了解.根据我们的示例代码就可以发行自己的以太坊代币. 什么是ERC20 可以把ERC20简单理解成以太 ...

  2. 一键创建以太坊ERC20代币教程

    30秒极速创建以太坊ERC20代币 傻瓜式创建,界面化创建,自动创建代币,简单好用 合约采用新版 5.10 新版合约编译器,合约代码100%安全无任何漏洞 下面是详细的使用和创建教程 1.点击创建ER ...

  3. 10分钟 5步 发布以太坊 ERC20 代币

    1.安装 METAMASK Brings Ethereum to your browser 一个可以浏览器上进行操作的以太坊钱包,推荐 Chrome. Chrome 插件安装地址: https://c ...

  4. erc20代币合约

    看这篇文章需要对以太坊,智能合约,代币等概念有基本的了解. 什么是ERC20 可以把ERC20简单理解成以太坊上的一个代币协议,所有基于以太坊开发的代币合约都遵守这个协议.遵守这些协议的代币我们可以认 ...

  5. 通过以太坊发行代币(token)

    2017年开始,区块链ICO项目层出不穷,市场热度一波更胜一波,很多ICO都是通过以太坊智能合约发行自己的代币(token),具体怎样才能发行代币呢?本文进行具体详细的介绍. 准备工作 以太坊官网ER ...

  6. 零门槛,包教会。让你在5分钟内使用以太坊ERC20智能合约发行属于自己的空气币

    前言 目前区块链是互联网中最最火的风口,没有之一.我周围的很多朋友也加入了“炒币”行列,但很不幸,几乎都被“割韭菜”了.而经过我的几天研究,发现,如果自己要发行一种空气币,简直太简单了.只需要下面几个 ...

  7. Solidity合约间的调用 -Solidity通过合约转ERC20代币

    Solidity通过合约转ERC20代币   ERC20代币并不能像Ether一样使用sendTo.transfer(amt)来转账,ERC20代币只能通过token中定义的transfer方法来转账 ...

  8. Solidity通过合约转ERC20代币

    ERC20代币并不能像Ether一样使用sendTo.transfer(amt)来转账,ERC20代币只能通过token中定义的transfer方法来转账,每个账户的余额信息也只保存在token合约的 ...

  9. 以太坊上发行ERC20代币

    ERC20 代币生成 环境 虚拟主机: ubuntu 18虚拟机 宿主主机: win10; ip:192.168.0.160 1.部署以太坊 1.1 安装GO 安装go,并编译geth 将下载好的go ...

随机推荐

  1. CHAPITRE III

    Il me fallut longtemps pour comprendre d'où il venait. Le petit prince, qui me posait beaucoup de qu ...

  2. Lagrange 乘子法求最优解

    clc clear syms x y z r1 r2 w f=x^+y^+z^+w^; g1=*x-y+z-w-; g2=x+y-z+w-; h=f-r1*g1 -r2*g2; hx=diff(h,x ...

  3. 相似性度量 Aprioir算法

    第三章 标称:转换成0,1来算,或者用非对称二元属性 二元:x1,x2的分布取00,01,10,11的二元属性个数,列表,算比例.不对称的二元属性就忽略00的属性个数 序数:转换成排位rif,度量:r ...

  4. hadoop flume 架构及监控的部署

    1 Flume架构解释  Flume概念 Flume是一个分布式 ,可靠的,和高可用的,海量的日志聚合系统 支持在系统中定制各类的数据发送方 用于收集数据 提供简单的数据提取能力 并写入到各种接受方 ...

  5. 比较jquery中的after(),append(),appendTo()方法

    html页面: <p id="myp1">我的兴趣爱好是:</p> <button id="b1">after函数</ ...

  6. Ubuntu 12.10 安装VirtualBox增强功能

    原文链接:http://fengbaoxp.iteye.com/blog/1871825 Ubuntu 12.10 Desktop         首先,通过VirtualBox菜单(设备->安 ...

  7. String、Stringbuffer、Stringbuilder三者之间的区别

    1.首先说运行速度,速度由快到慢排列:StringBuilder > StringBuffer > String String最慢的原因: String为字符串常量,而StringBuil ...

  8. poj2094

    很不错的一道题,很让我见识到了差分序列的运用的神奇之处..一下是从北邮BBS看到的题解,写得很清楚..这边就直接转过来. uRLhttp://bbs.byr.cn/#!article/ACM_ICPC ...

  9. delphi 小数点四舍五入问题

    function ARoundN(v: Double; n: Integer): Double; var I:Integer; begin result:=v; do begin result:=re ...

  10. Android-多线程安全问题-synchronized

    先看一个售票案例Demo,多线程程序对共享数据操作引发的安全问题: package android.java.thread09; /** * 售票线程 */ class Booking impleme ...