00:00
好,接下来就会复杂一点了,接下来这个子货币是什么意思呢?这其实就是我们经常所说的基于以太坊不是能发币吗?呃,不是有各种各样的token吗?怎么样去发呢?它这个合约到底是应该什么样的一个状态呢?里面有哪些基本的要素呢?我们就想构建一个这样的东西。那这样的东西里边可能会包含哪些内容?我们首先先想一想。首先,这样的合约。里边我们能想到的就是它一定得保存一个。就是每个人的账户对吧,就我们要发一个子子货币,或者发一个代币,那所有人在这个我们的这个合约里边就一定得有一个它对应的balance。要不然的话,我们这个怎么能叫货币呢,你连账户都查不出来,每个人有多少钱都查不出来,所以这是肯定要有的一个数据结构,那这个数据结构用什么样的类型去存储,这我们直接一个就不行了,对吧,你一个只能存一个数,这个看起来应该是用一个数组,可能会好一点。
01:11
对吧,数组存一组数存balance,但是也不对,那这个数组的话,那我们相当于就要就是给每个用户有一个编号,对吧,我们还得存一个用户对应的编号。那其实这里面有一个简单的想法,就是。我们用一个映射,用一个mapping,对,用一个类似于哈希表的一个结构,我们直接把用户的地址映射到它对应的一个balance上面去,那这样的话就是一个地址对应一个余额,一个地址对应一个余额,这就完了。这是一个就是在这个,呃,这样的一个子货币里边,基本的一个数据结构啊,当然了,在这个子货币里边,他想的就多一点,他就想那我们这个币怎么发呢。
02:04
就是我们首先这是可以存储别人的余额了,那这个币怎么样来呢?这个币肯定是凭空来的嘛,它既然不像以太坊那样要挖矿,那我们。那我们也不能凭空来,那我们就也定义一个挖矿的机制,或者说铸币的机制,所以它在这个里边就定义了,大家可以看到前面有一个mter meter,其实就是定义了一个铸币者,相当于是就是谁有权限去铸币,然后这个人呢,他有一个方法就叫MT就可以去铸币,这就相当于凭空去造币,造我们的货币。当然了,在这个子货币里边还得有一个基本方法,就是你得能转啊,你你不能说我这个里边就是每个人一个数,然后这个数都改不了,那就没用了,就只是你一个人能能铸币,能能造币,在那玩的很嗨,那别人不能转也不行,所以肯定还有一个基本方法,就是转币的方法,在这个里面大家可以看到。
03:06
上边的这个address public,这就是一个就是铸币者。然后下边的map publics,这是就是我们说的。从地址到他的余额的那个映射,等一下这个具体的数据,数据类型,咱们到时候再详细的讲解啊,上午可能时间不太够了,然后他还定义了一个event,这是一个事件。这个到时候我们再再说,这是它的一个特殊的东西啊,然后下面就是constructor怎么样,然后它定义了一个叫mean的方式,这个就是铸币,就是只要调这个方法就可以去发币。下面是还有一个方法叫sand,那sand就很好理解了,那就是我们一个地址转到另外一个地址去,所以这是它看起来很简单,但是这其实已经有一点设计的东西在里面了,对吧,就是我们要。
04:04
实现什么样的功能,然后用什么样的数据结构构造什么样的函数方法去实现这个功能,大家可以先简单的看一看,然后大家如果要是想做一些操作的话,我们在remix里面,大家可以随时的敲一些自己想敲的代码,对吧?可以尝试加加减减,加减乘除数据类型想试的话也可以试,然后复杂的数据类型,就是更多的数据类型之后面后面我们会留下专门的时间给大家讲解那些数据类型。好,那现在大家先是是自己看一看,还是说我们就直接在里面开始敲。十分钟,咱们现在开始敲行,那我们就不留时间了啊,就是敲到多少算多少。好,我们新建一个文件,比方说我们这个就叫泡影吧,哦,我这个是好像我已经见过这个泡影文件,我把这个删了吧。
05:18
水内好像不太好使的样子。重新建立一个。好,我们建立一个,那么。还是一样啊,没有写错吧,Solidity,呃,我们就还是默认先都用这个0.4.22吧。接下来contract point,这是我们的,这是我们的合约,然后接下来我们就想到刚才我们定义的数据类型。一个是我们说有一个人可以凭空发力,那这个人的数据类型是什么呢?我们怎么样确定这个人是跟我们比方说我,我创建这个合约的人有关的。
06:11
那创建这个合约的人肯定他有一个参数就是地址了,那我们就把这个M铸币者也定义成一个地址类型。这是我们在。在我们的这个整个扫地里面,非常特殊的一个数据类型啊,对吧,大家可以看到啊address。然后我们这里可以把它定义成public,对吧,就铸币者是大家可见的。好。然后接下来我们再去看,我们需要有一个从每一个地址到。他们所有的余额,代币余额里边的一个映射,那这个映射我们就是叫做mapping,这个数据结构在solid里面叫做map mapping,然后它后面会有一个类型的指定,比方说我们是从地址到余额的一个指定,我们可以指定address。
07:15
这样,那后面是他的,呃,名字叫我们就叫balances吧,Balance。呃,这个balance就我们就最好不要给他弄成public让去访问了,因为大家知道我们前面说了,就是在这个以太以太坊,在整个系统的系统存储里边,如果要是这种mapping,还有数组之类的东西,它是没有办法,因为它它是会直接散列到一个非常广大的数据存储空间里面去,如果我们想要去直接拿到所有的address和所有的UN的话,这个会非常的消耗我们的系统资源,所以几乎直接便利是不可能的。
08:04
那如果我们这里去去直接给他一个public,让大家可以访问这个所有的balances的话,这个其实是不太现实,或者说不应该做的一件事情啊,所以我们这个先先不给他public的类型啊,好,那接下来我们看一个constructor。我们定义一个。定义一个构造函数,大家可以想到构造函数在创建的时候应该有什么样的特点呢?我们至少得告诉谁是铸币者对吧?因为这个铸币者之后可能会有很大的权利。所以我们应该。去给一个,呃,这个可以没有没有参数啊,因为我们其实是知道谁发的这个消息的,对吧,假如说我们是要指定我们自己发送这个创建这个合约的话,把自己当成铸笔者的话,那么我们直接指定meter等于。
09:06
应该是谁对MSG点三好,我们把自己定义成这铸币,呃,当然了,这个constructor我们可以加一个public啊,好,这就是constructor,然后接下来有两个方法,我们想到一个是铸币上来之后可以凭空发币,那这个铸币方法meant,呃,我们设想是什么样呢?那就是凭空发币,那你还得知道是发给谁呀。所以我们应该有一个比如说receiver之类的东西,那这个就应该是也是一个地址类型了,对不对,直接发到他的地址上,所以在我们这里边所有的人对应的都是地址,对吧?所以这其实也是一个很好的一个对应关系,我们不用再去建一个比方说像用户列表啊这样的一个维护,就是指定用户的编号,指定用户的地址,呃,我们这里就直接拿地址来指代用户就可以了,那另外就是你要发币发多少呢?我们肯定会有一个want,好,这就是我们现在能够想到的比较直观的一个。
10:25
定义,呃,Public,那这个还是这个方法,我们先放在这儿啊,可能里边会涉及到一些别的一些逻辑,我们先把这个框架先搭好,然后另外一个就是方式,我们还应该有什么对,应该有一个转币,比方说transfer啊,我们不要transfer,因为transfer是一个关键字,对吧,当然其实也也可以用啊。我们定义一个send,那send同样就是你要给谁去发呢?那谁send,这个我们肯定是知道的,就是谁调用,那就是谁send,那如果要是说我们已经知道了谁是发就是thunder,谁是发送者,那我们肯定这里只要定义一个接收者就可以了。
11:13
也是一个receiver,呃,然后其实也一样的,也是一个amount,对吧,Send多少public好就是就是这样的两个方法,那接下来我们其实就是要看怎么样去把里边的东西填充起来。接下来我们要能够发币,发币的过程我们想的是就由我们自己来来发,那只要就是说传入一个发给谁,给他多少这就可以了,那我们只要是前面判断了,呃呃,当然了,这个就是说这个方法只能由我们定义的mter来来调用,要不然的话,我们前面定义这个铸币人就没有什么意义了,对吧?所以铸币这个环节是有一个要求的,这个要求。
12:08
就必须是我们用require这个这个语句来做一个强制性的要求,Require什么呢?就是要求现在的。MSG的三必须等于我们定义好的名特,这就是我们一个要求,当现在调用这个M函数,函数的这个人,就是我们之前定义好的me的时候,那这个时候我就可以去把要发的这些币,这个数量的币给到这个receiver,那在我们这里边是什么什么情况呢?其实不不存在转币对吧,咱们是需要调那个转币的transfer方法吗?
13:03
串词方法要转的话,转的就是以态。这里我们只是要转我们自己定义的这个子货币而已,所以说这里边不存在要转币的这个事情,所以我们所谓的转币其实就是把balances的receiver里边应该怎么样加上一个数,对吧?加等于amount,这其实就是我们经常这就是大家其实在别的编程语言里边肯定都是很熟悉的一种写法了,就是不是很难啊,大家一看就知道它想要表达什么意思,然后接下来下面还有一个,我们还定义了另外一个函数,就是我们要去散,那就是说这是所有人都可以调的一个方法,这个方法定义出来之后,谁去调谁就会给别人去发送一定数额的子货币。
14:03
所以在这个里边我们就不需要去require,呃,它TH等于M或者是等于谁了,对吧?谁都可以调的,但是这里边我们也应该有一个简单的要求,这就是在转账的时候,一般情况都会有的要求,要转这么多子货币,那得要求我们余额里面首先得有吧,所以这应该也是非常好想到的啊,Require balance,这个应该是receiver吗?不是了,那这应该是对S应该要大于等于amount,对吧?在这样的一个条件下,那我们确保它的余额是足够用的,要发这么多币,它余额里边大于等于这个数量,那么我们就允许他去把这个币转给别人,转币的过程当中,我们一般都是,呃,这就跟银行的操作一样了,你要给别人转币的话,那就把你的账户先扣掉,然后别人的账户加上这个转币过程就完成了,所以我们这里面操作是一模一样的啊,呃,那就是balances Ms这点三,这是我们调用这个函数的人,他要给别人转B,所以他是应该要解。
15:32
减等于amount,呃,大家熟悉这个写法对吧?这,这应该跟我们这个经典的写法都是一样的,减等于就表示balances。他现在要做一个赋值,那是要把本来balances message send的值减掉amount之后再付给balances message send,所以是用减等于的方式,那同样他减了之后,他要给的这个人就得加上,那就是balance receiver,加等于amount。好,这其实就完成了我们这里需要做的这一个转账的工作。
16:17
呃,当然了,呃,大家可以看到整个这个过程当中其实非常的简单,我们没有做更多的安全校验。比如说这里有可能有什么样的安全风险呢?大家能想到,呃,一时半会想不到是吧,就是在这里做减法和加法的时候,其实咱们没有做任何的限制,那对于一个u in,它本来是256位的数,256位的无符号数,那么理论上它其实是存在一个上限的,对吧?如果说要是有上限的话,它减到一定程度,或者加到一定程度,是不是就有可能会溢出?
17:13
那溢出的时候会怎么样呢?对,加如果大家可以想到,呃,加到上线256,再加到上限的话,那就相当于归零了,对吧?那减的话可能就更加夸张一点,如果要是减下去,减成负的情况,按道理其实它就会会变成很大的一个数,对吧?所以大家这里其实已经可以看到它本来这里是有一些安全风险,当然我们这里只是简单的把它实现一下,所以我们不考虑那么多。呃,但是我们一定要有这样的意识,其实在之前就是,呃,一开始刚刚兴起,很多人这个搞ICO的时候,他们去写自己的代币合约,其实可能就没有注意太多安全性上的考虑,有一些人的合约里面就出现了这样的一处漏洞啊,或者是怎么样,曾经应该是去年的时候还是什么时候,呃,就是有具体那个那个代币叫什么名字,我一下忘记了啊,不知道,可能有同学也也听说过,当时有一个代币就是直接爆出了合约里边有艺术漏洞,就是类似这样的一个漏洞,它有一个地方的加减运算没有做安全限制,所以就导致呃报出来之后,在某种情况下,一旦溢出,那别人的账户就会突然变成很多钱。
18:42
所以他他被爆出了这个漏洞之后,而且这个还是已经就是真正的发行上了交易所的一个一个代币,所以就导致瞬间币值就归零了,就所以就是风险确实还是蛮大的,就是发币也容易,那就是归零也容易,其实就是这样的一种状况,双刃剑好,另外我们再说一个,大家可以对比,我们叫呃,就是PPT里边,我们PPT里边还多了一项东西,就是这个。
19:15
Event一个事件,这个是做什么用的呢?那这个其实就是说要在我们转币的时候,这里是定义了一个散的事件。要在我们转币的时候发出一个事件来,它主要的作用就是让我们更容易去去跟踪整个区块链的log。它的作用就是在于当我们在下面调用这个三事件的时候,可以把后边的参数传进来,然后我们在外部去监听这个事件的时候,就可以直接获取到它现在散的这些参数。所以我们看它的定义,上面定义的方法是event sent,然后后面定义了它要带的参数,这就相当于就像我们函数的这个呃定义一样,对吧,只不过是用了一个event的一个关键字。
20:11
而下面调用的时候,我们看到他是发了一个呃,It set,所以就是发布一个这样的事件,后面呢,传入的就是具体的参数了,那这边定义的是from to和amount,那我们这边肯定就是from是ther,然后to是receiver want,把这个画出来就可以了,呃这里我们就不详细的实现了,我们在这里当然大家如果想呃,我们现在因为没有验证,所以说大家可以去写一下,看看这个语法会不会报错,只能是做到这样对吧?三呃一般是会大写啊。我们这里是大写的吧,看一下对一般事件是会用大写来表示,Address from address to amount,这就是我们定义的一个事件,然后我们在下面就可以一个。
21:17
Ms receiver,还有amount,哎,我到这里报错了。哦,这个关键字写错了吧,对吧?好,所以大家可以看到就是哦,大家是说就是这个是直接放到了整个那个Co这个合约的最外层了,对吧?但实际上我们不应该在最外层去去调用这个发布事件,因为这个合约就不知道编译器就不知道你这是要干什么了,因为在外面并不是一个函数,我们没有办法去调用到这个地方,所以它并不是一个定义,所以不可能把它放在外面。
22:20
好,我们就在这里把它,我们可以看一下这里这个是什么。啊,大家可以看到这里的warning,它报的是什么呢?他说我们可以用这个assert这样的一个断言。如果你,呃,永远不希望他是false。然后下面是说你可以用一个require这个方法。如果说它可以是false。所以这是什么意思呢?这其实是在跟大家说,我们在做这个条件判断的时候用什么,它这里提供的两两种用法是一个叫做require,一个叫做assert,呃,这里可以简单的先提一句,就是它这个其实它只是一个提醒啊,这个不算真正的warning,所以我们在这里用的是require require表示什么呢?就是表示它这里边后面的这个条件是可以不为真,可以为假的,因为他说就是有可能是false,对吧。
23:30
那如果要是什么时候用assert呢?Assert意思就是说它里边这个一定是为真的,也就是说如果它为假的话,它其实就是相当于这是我们内部的逻辑错误,才会用assert来断言。那就相当于是别人输入了参数,有可能错误,那这个确实是有可能的,好,我们在这里已经编辑成功,我们来deploy,然后跑一下看一看它的效果。
24:02
好,大家可以看到我们deploy之后生成的几个参数有什么呢?有一个mter,这就是我们定义的public变量,所以这个状态变量我们是直接可以用M这个来查询到的,大家可以看现在这个M特是是谁,就是我们现在的。发布的这个com对吧,CA3尾,尾数是A733C,应该就是刚才我们发布合约的这一个账号,所以特就是发合约的人那。MT和散两个方法也都列在了这里,我们现在调一个试试啊。呃,这里可以看到,我们要输一个receiver,还要输一个数,那我们选这边一个吧。我们点这个就可以copy啊。
25:00
大家注意要切回来,就是我这里如果是选择这个javascript vm的话,还得再切回来。好,比方说给他1万个,大家可以看,这个已经成功了。然后比方说我们想啊,大家可以看到就是。这个里边我们有一个问题,就是说没有给出可以查他的balance的一个方法,对吧,所以这个可能是会有问题的,那这是因为我们一开始说,呃,我们不想让这个balance全部暴露出来。呃,但是这个里边如果说我们想直观的说就是想要查的话,那我们就直接把它定义成public,只不过查的时候我们不要去直接访问,就是便利的方式去访问balances,我们要给定balances里边的某一个address,给定值去查,这个肯定是可以的,对吧,就相当于是在一个哈希表里边给定key去查value,这个是肯定是可以的,所以我们这里在com一下,然后把这个删掉,我们重新来deploy一下。
26:20
好,现在大家就可以看到balances,这里就多了一个可以直接查询的地方,英特尔我们还是看一下,还是这个,那balances,呃,现在肯定就不行,如如果直接什么都不给的话是不行的,对吧?好,我们给一个这个刚才复制的这个地址来看一下,现在它是零,这个肯定没问题。好,那我们在这里给一个1万。好,大家可以看到现在我们在查。诶,刚刚才我点了两次是吧,我这里没有鼠标,所以用这个触摸板在这里点的话,可能确实是容易出现这种情况,好,我点一次,刚才大家看到这里好像谈了两次交易,对吧?对,这里有两笔交易,所以如果大家不确定的话,可以在这边看这个log,刚才我又点了一次,我们看一下现在是3万,所以是这样的一个状态那。
27:24
我们现在如果再把我们自己的这个copy一下,我们来查询一下,我们尽管是铸币人,但是如果我们没有调用铸币方法给自己发币的话,那肯定现在还是零好,那我们现在想要去散一下,那我们把这个写到这里,比方说他已经有3万了,我们就发个5000。大家说我现在如果要散,能成功吗?能成功是吧,好,我们试一下。诶,这里报错。
28:02
为什么会报错呢?咱们看一下啊,Transact to coin error,他说了对吧。The constructor should be payable if you send value。呃,这这个倒没有啊,这只是他的一个一个提示的消息,大家想一想,我刚才send的时候是要给我们的这个地址去发,对吧,那发送人是谁。还是他自己对吧,所以现在如果咱们上面这里的这个调用合约的这个人,发送发送交易的这个人没有改变的话,那就还是自己,那自己这个时候他是不是应该还没有余额啊啊没有余额,那你要给自己发5000,那肯定就有问题了,所以我们切换一下,切换到刚才我们有余额的这个数量比较大的这个,好,我们再三。
29:03
来看现在成功了,好,我们查一下,哎,现在有5000。那我们再查一下,刚才他是3万对吧。Balance变成了25000。所以这其实就是实现了一个非常简单的货币的一个系统,我们在里边有一个M,它可以传入一个地址和一个数量,就可以给对应的地址账户去发币,然后呢,下面就还可以大家自由的去转账,自由的去转币,所以这就是我们这一个简单的一个实现。
我来说两句