孤荷凌寒自学python第125天区块链039以太坊的 erc20代币09
【主要内容】
今天继续使用erc20标准规范按另一篇网络博文的教程进行复制代码来批注一个可以发行代币的智能合约。学习共用时36分钟。
(此外整理作笔记花费了约45分钟)
详细学习过程见文末学习过程屏幕录像。
【学习笔记】
一、今天参考别人的代码,然后加上了个人注释:
学习的博文地址是:https://blog.csdn.net/hantangduhey/article/details/80714656
今天认真通读源代码,并加上个人注释,感觉自己通过近二十天的学习(比较慢咯)能够读懂这些solidity代码,并完整批注了:
```
pragma solidity ^0.4.24;
//作者原创博文地址:https://blog.csdn.net/hantangduhey/article/details/80714656,此处我的引用只用于学习。
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
防止整数溢出问题
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
contract StandardToken {
//使用SafeMath
using SafeMath for uint256;
//代币名称
string public name;
//代币缩写
string public symbol;
//代币小数位数(一个代币可以分为多少份)
uint8 public decimals;
//代币总数
uint256 public totalSupply;
//交易的发起方(谁调用这个方法,谁就是交易的发起方)把_value数量的代币发送到_to账户
function transfer(address _to, uint256 _value) public returns (bool success);
//从_from账户里转出_value数量的代币到_to账户
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
//交易的发起方把_value数量的代币的使用权交给_spender,然后_spender才能调用transferFrom方法把授权发起方账户里的钱转给另外一个人
function approve(address _spender, uint256 _value) public returns (bool success);
//查询_spender目前还有多少_owner账户代币的使用权
function allowance(address _owner, address _spender) public constant returns (uint256 remaining);
//转账成功的事件
event Transfer(address indexed _from, address indexed _to, uint256 _value);
//使用权委托成功的事件
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
//设置代币控制合约的管理员(即合约发起与部署者的权利声明与管理控制)
contract Owned {
// modifier(函数修改器),所有使用了些修改器的合约内函数都要作此用户权限检查,表示必须是权力所有者才能do something,类似administrator的意思
modifier onlyOwner() {
require(msg.sender == owner);
_;//do something 此短横线指代所有后续命令
}
//权力所有者的地址,即合约部署者的地址
address public owner;
//合约创建的时候执行,执行合约的人是第一个owner
//下面的合约建构体只执行一次,即合约部署时才执行,后续调用合约不会再执行此建构体,则保证永久记录下合约的拥有者(部署者)的节点地址
constructor() public {
owner = msg.sender;
}
//新的owner,初始为空地址,类似null
//似乎这里可以设置新的合约管理员!?
address newOwner=0x0;
//更换owner成功的事件,设置合约管理员成功的事件广播
event OwnerUpdate(address _prevOwner, address _newOwner);
//现任owner把所有权交给新的owner(需要新的owner调用acceptOwnership方法才会生效)
//--此合约竟然可以更改智能合约的拥有者!!--新的owner需要同意接受,才会真正更换。
function changeOwner(address _newOwner) public onlyOwner {
require(_newOwner != owner);
newOwner = _newOwner; //这里还并没有真正更换智能合约的拥有者(控制 者),下一个函数被调用执行后,再真正更改。
}
//新的owner接受所有权,权力交替正式生效
//此函数方法只能由接受智能合约新拥有者身份的那个节点来调用——require(msg.sender == newOwner);这儿作了限制
function acceptOwnership() public{
require(msg.sender == newOwner);
emit OwnerUpdate(owner, newOwner);
owner = newOwner; //这时才真正更换了智能合约的拥有者
newOwner = 0x0;
}
}
//代币的控制合约
contract Controlled is Owned{
//创世vip,就是说,将部署合约的节点地址首先设置为 vip节点,setExclude方法就是向全局变量exlude映射表中添加新的vip地址的。
//此建构函数只执行一次,就是在部署合约时执行那一次。
constructor() public {
setExclude(msg.sender,true);
}
// 控制代币是否可以交易,true代表可以(exclude里的账户不受此限制,具体实现在下面的transferAllowed里)
bool public transferEnabled = true;
// 是否启用账户锁定功能,true代表启用
bool lockFlag=true;
// 锁定的账户集合,address账户,bool是否被锁,true:被锁定,当lockFlag=true时,恭喜,你转不了账了,哈哈
mapping(address => bool) locked;
// 拥有特权用户,不受transferEnabled和lockFlag的限制,vip啊,bool为true代表vip有效
mapping(address => bool) exclude; //映射全局变量,每个地址,后面有年bool值,如果地址映射 的bool值为true,则此地址就是vip身份
//设置transferEnabled值,调用此函数来进行【是否允许代币交易的全局开关】,只有合约的当前拥有节点才能调用 此函数,因为加上了onlyOwner函数修改器
function enableTransfer(bool _enable) public onlyOwner returns (bool success){
transferEnabled=_enable;
return true;
}
//设置lockFlag值,调用此函数来进行【是否冻结锁定所有在黑名单中的所有节点的全局开关】,只有合约的当前拥有节点才能调用 此函数,因为加上了onlyOwner函数修改器
function disableLock(bool _enable) public onlyOwner returns (bool success){
lockFlag=_enable;
return true;
}
// 把_addr加到锁定账户里,拉黑名单。。。 添加专门的用户节点地址黑名单,只有合约的当前拥有节点才能调用 此函数,因为加上了onlyOwner函数修改器
function addLock(address _addr) public onlyOwner returns (bool success){
require(_addr!=msg.sender); //避免将合约拥有者的节点地址添加到黑名单中
locked[_addr]=true;
return true;
}
//设置vip用户,只有合约的当前拥有节点才能调用 此函数,因为加上了onlyOwner函数修改器
function setExclude(address _addr,bool _enable) public onlyOwner returns (bool success){
exclude[_addr]=_enable;
return true;
}
//解锁_addr用户,将用户节点从黑名单中移出,只有合约的当前拥有节点才能调用 此函数,因为加上了onlyOwner函数修改器
function removeLock(address _addr) public onlyOwner returns (bool success){
locked[_addr]=false;
return true;
}
//控制合约 核心实现 ---此函数修改器,保证对用户节点是否被限制交易和被冻结账户的全局控制
modifier transferAllowed(address _addr) {
//第一行,就保证了所有vip用户节点不受控制
if (!exclude[_addr]) {
//如果全局设置禁止交易,则直接回复:当前不许交易
require(transferEnabled,"transfer is not enabeled now!");
//下一行先检查全局设置是否冻结黑名单中的用户节点
if(lockFlag){
//如果全局设置已要求冻结黑名单中的用户节点,则开始冻结
require(!locked[_addr],"you are locked!");
}
}
_;
}
}
//修改为我自己的代币,作者原创博文地址:https://blog.csdn.net/hantangduhey/article/details/80714656,此处我的引用只用于学习。
contract CloudImageToken is StandardToken,Controlled {
//账户集合
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) internal allowed;
//合约的建构函数只执行一次,仅在合约部署时执行--------
constructor() public {
totalSupply = 100000000;//1亿,此合约目前是一次性将所有币的总数规定好,没有后续增发铸币的功能。
name = "CloudImage Token";
symbol = "CI";
decimals = 0;
balanceOf[msg.sender] = totalSupply;
}
//合约调用节点向另一个节点发送代币,加上了transferAllowed函数修改器,则接受合约的全局控制
function transfer(address _to, uint256 _value) public transferAllowed(msg.sender) returns (bool success) {
require(_to != address(0));
require(_value <= balanceOf[msg.sender]);
balanceOf[msg.sender] = balanceOf[msg.sender].sub(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
//任意节点向另一个节点发送代币,这意味着,这是授权模式下才能执行的,即是说合约的调用节点是得到了发送代币节点的授权的。加上了transferAllowed函数修改器,则接受合约的全局控制
function transferFrom(address _from, address _to, uint256 _value) public transferAllowed(_from) returns (bool success) {
require(_to != address(0));
require(_value <= balanceOf[_from]);
require(_value <= allowed[_from][msg.sender]); //所以这儿增加检查了,授权当前调用合约的节点作用发送代币的节点的授权代币总量余额。
balanceOf[_from] = balanceOf[_from].sub(_value);
balanceOf[_to] = balanceOf[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
//授权操作的函数,此函数就没有添加transferAllowed函数修改器。授权操作对所有用户节点都是任何时候都 可用的。
function approve(address _spender, uint256 _value) public returns (bool success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
//此静态函数(使用了view修饰词,也可用contant),用于返回使用的代币总量余额。可以查询并返回任意授权方与接受授权方节点对的授权代币全额情况
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
return allowed[_owner][_spender];
}
}
```
【今天的自学感悟分享】
你相信吗?学习能力是有档次的!
最低档次的学习能力就是基本没有自主学习的能力,这时只能被逼着学,如多数人的学校学习阶段。
稍低档次的学习能力是可以主动地进行自主学习而不需要外力的逼迫,这时还能应付一些应试考核之类的东西。
中档次的学习能力是完全可以凭自己的力量独立完成规定内容的学习,比如自学考试获取学历,能够轻松自学参加职业考试等。
高档次的学习能力是可以独立自主的选择要学习的领域,并独立确定要选用的教材和学习的内容,而后可以完全凭自己的力量独立完成自选的学习内容,比如那些自学成材的,我们所称的高手在民间的高人就是此类。
最高档次的自学能力是可以在完全没有可以学习的内容的情况下,独立探索并学习前人没有传承下来的全新领域的新知识,进而出现新发明的过程,这是*的学习能力,是大师与发明家的独立自学能力的体现。
那么我认为只要达到高档次的学习能力水平时,才算得上真正的学习。
欢迎共同探讨
我建立【就是要学】社群的初衷就是将渴望与我一样追求自主独立的生活的朋友 ,特别是还有大把青春可以去试错的年轻朋友聚集到一起,在这个人以类聚的时代,我们在一起, 互相交流,坚持每天成长,欢迎来到【就是要学】社群QQ群:646854445
或访问:www.941xue.com
【关于坚持自学的例行说明】
最后例行说明下,我为什么要坚持自学。
“如果我不曾见过太阳,我本可以忍受黑暗,然而阳光已使我的荒凉,成为更新的荒凉。”
——艾米莉·狄金森
如果要问我对自己的前半生如何看待时,我想昨天和今天的答案都将完全不同。
昨天的我,生活在荒凉的满意之中,自觉怡然自得,拿着包身包月的工资,听着仁慈的命令,过着几乎一成不变的生活;时而与周遭的人儿和睦互往,时而唇舌相抵斤斤计较,演出着生活的鸡毛蒜皮,工作的吹拉弹唱;忘我,忘我,才能融入这平和无奇的乐章中,迈着细碎的步伐,原地踏步。那时的我觉得这就是悠然自得的听天由命的平凡人生,也就是我的宿命了。
可是某一天,我见到了不一样的太阳以及太阳下不一样的人生光景——那并不荒凉。
今天的我,生活在荒凉的痛苦之中,自觉渴望改变,迈着不知所措的步伐,看着流逝的年华,睁着悔恨错失一切的双眼… …
我知道我将再无法回到过去的我,只有改变才是唯一正确的方向。
一、为什么一把年纪还在学习
放弃很多去聚餐,去HI歌,去游玩,去看电影,去追剧……的时间,然后进行着这个年纪似乎已不应当再进行的学习,引来身边人们无尽的不解与鄙夷甚至可怜……
但我不想放弃终身学习的誓言。
因为——
我对我今天的生活现状并不认同!
罗伯特清崎告诉过我们,反省自己当下的生活是不是自己想要的,这难道不是最好的动力与答案?
走过了大半生,然后才发现曾经、当下所正在进行的人生并不是自己想要的,那是一种怎样的体验?
只有心中真切的感受才能回答这个问题,而任凭再丰富的语言也是无法描绘出来的。
经历半生的跋涉,却发现走得并不正确,有多少人有勇气承认自己过去的一切都是错误的呢?
而我愿意告诉过去的我:“你错了!”
那么已经历半生错误,年岁之大又压于头顶,还有希望从这架的*的半端重新爬下,再蹒跚着爬上另一架*吗?
我宁愿相信还有希望!
这便是我为什么要继续坚持终身学习下去的全部理由。
二、这个年纪还在学这些技术有意义吗
纯的技术对这把年纪其实已没有意义。
但兴趣可以超越意义。
但技术可以引来思想的变革,这才是意义。
投资自己的头脑 ,改革自己的思想,这是最保值,更长远的投资,过去我从来没有投资过,错过太多,那就从投资自己头脑开始吧。
罗伯特清崎告诉我们,真正的富有是时间的富有;真正的*是可以决定自己愿意做什么的*。
因为我愿意做我兴趣所在的事,所以我希望我有*选择的那一天,虽然今天离那一天可能还是那么遥远,但我愿意相信,每天多赶几步,离希望就更近一步。
再者,虽然我可能再已无法完全完整的掌握这些技术了,但技术本身却可以启迪心的觉醒,激发灵感,那么只要多了解一点,我相信我将离那个正离我而去跑得越来越快的未来更近一点,不至于被未知的那个未来抛弃得太远。
于是我怎能放弃追逐求索的步伐?
我要坚信:感觉太迟的时候,也许还不算太迟。
【同步语音笔记】
https://www.ximalaya.com/keji/19103006/271995817
【学习过程屏幕录屏】
https://www.bilibili.com/video/av97423188/