2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 以太坊ERC20代币合约案例

以太坊ERC20代币合约案例

时间:2022-05-05 09:25:03

相关推荐

以太坊ERC20代币合约案例

一.ERC20代币合约与web3调用

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

二.ERC20合约标准

【官方链接】

contract ERC20 {//**********9个函数*******//1.代币的名字,如:"黑马币"function name() constant public returns (string name);//2.代币的简称,例如:HMBfunction 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的tokenfunction 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 senderbalanceOf[_from] -= _value;// Add the same to the recipientbalanceOf[_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 allowanceallowance[_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) publicreturns (bool success) {allowance[msg.sender][_spender] = _value;return true;}/*** 设置允许一个地址(合约)以我(创建交易者)的名义可最多花费的代币数。*-非ERC20标准* @param _spender 被授权的地址(合约)* @param _value 最大可花费代币数* @param _extraData 发送给合约的附加数据*/function approveAndCall(address _spender, uint256 _value, bytes _extraData)publicreturns (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 enoughbalanceOf[msg.sender] -= _value; // Subtract from the sendertotalSupply -= _value; // Updates totalSupplyBurn(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 enoughrequire(_value <= allowance[_from][msg.sender]); // Check allowancebalanceOf[_from] -= _value;// Subtract from the targeted balanceallowance[_from][msg.sender] -= _value; // Subtract from the sender's allowancetotalSupply -= _value;// Update totalSupplyBurn(_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 = pile(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 导入 编译好的 合约的 字节代码 和 abiconst 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钱包providerconst 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();//0x6c57CD10B4384C605aC748937b6cC1dF6C8eddA9web3.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 金额给 usrAdrToasync 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);}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。