00:00
好,那接下来我们再朝着现在实际的这个方向来改动,改进一下我们的这一个代币合约,或者说货币的合约,这个合约里边我们发现啊,就是在这个里边,我们是定义了一个M特,就是有一个铸币人,他相当于对我们这个代币呢,有无限的权利。就是一开始我们并没有设定这个代币有多少个,所以这个代币可以是无限的。而且这无限的代币,全部的发行权都在这个铸币人手里,他想给谁发就给谁发,想发多少就发多少。那如果说我们真的要是就是自己去做ICO,然后创建一个这样的币的话,相信肯定是没有人买单的,因为别人肯定会说,那所有的权利都在你手里边,我怎么知道你想给谁发币啊,我怎么知道你给别人发多少币啊,你上来之后这个权力太大,那肯定大家是是会认为这个是有问题的,对吧?所以实际在应用的过程当中呢,一般情况我们不会定义一个这样这么中心化的一个M。
01:18
让他完成这个所有的发币的动作,而实际当中我们会怎么做呢?正常的一个一个做法是我们会直接定义一个总量。就是我一般情况发行一个代币的时候,是在它的合约里边就设定了它的总量。所以我们简单的看一下,就是这里我可以直接给给大家看一下我参考的资料啊,大家可以看到。这里就是一个改进,呃,不能说改进吧,就是相对来说在设计理念上有所不同的另外一个代笔合约。
02:01
这个代币合约里面,大家看到就已经没有特这样一个概念了。它相对来讲好像比我们还简单了一些,对吧?它直接就有一个,呃,直接就是一个mapping,我们叫balances,它叫balance of,其实也是差不多的,只不过它这个查询起来好像就更语义明显一点,Balance of后面加一个地址,查出来的就是它对应的这一个balance余额,那大家看它其实下边,呃,它这个用的还是比较老的这种constructor对吧,它是直接function my token,这是跟它的这个合约明一样的一个。哎,我这个鼠标确实有点问题啊。合约明一样的一个呃函数,所以这就是作为它的构造函数来使用的,它在构造函数里边这总是一点就点成这样啊,它在构造函数里边传入了一个初始化的一个总量。
03:00
手撕了。然后。在初始化过程当中,他直接就把这个总量全部给到了三。所以这个比咱们那个好处在哪哪里呢?尽管它也全,就是所有的币控制权也都在这个mes center手里,但是这个总量是固定的,而且是公开的。至少这个币不会无限发。所以这是平常就是大家看到很多这个,呃,去去做这个ICO啊,去做代币发行啊,他们基本上采用的都是这种模式,好那么我们现在就就来具体实现一下这样的一种模式,那在这样一种模式下,我们的me就没有用了,对吧,直接可以把它删掉。呃,然后我们可以看到constructor里边。我们不需要就是像他一样用这个老的写法,我们还是用constructor就可以,Constructor里边它会定义一个,呃,不是address,会定义一个初始化的。
04:10
总数对吧,它叫initial supply。所以有了这个东西之后。我们在初始化的时候把总数传进来,然后把所有的这个总数的全部给到mes standard的余额,那就相当于初始化之后总量恒定,而且全部都由自己发行,就相当于是这样的一种货币,那我们这里应该怎么写呢?那就是balance message点等于对这里的initial来好,那同样这个铸币的这个方法就没什么用了,对吧,把它删掉。
05:01
同样下边我们send这个方法的话,那还是可以有一个receiver,有一个amount,这里我们require还是一样的,对吧,就是这个standard的数量要大于等于amount,然后呢,呃,就是standard的数量去减,然后receive的数量去加,在这里其实大家可以看到啊,刚刚才我给大家看的这个例子,它其实就。哎,这个这个点的真是,它其实就多了一重安全的验证,大家可以看一下,它除了我们判定班messages点三的余额要大于等于value之外,这是保证我们在做减法的时候不会溢出,对吧。另外我们还知道,假如说我们做加法的时候,这里这个。我们要接收货币的这一个人,他里边的余额如果加上Y6,超出我们的上限的话,256位的上限的话也是会有问题的,所以他还专门做了一个校验,就是balance,呃,To要加上value要大于等于balance of to,所以这个校练其实意思就是说做加法之后不要溢出,不要出现异常的状况,好,那我们也就学着它在这里加一句,这样require啊,Balances这个默认都是出require加上我们要。
06:49
大于。Balances receive其实应该还是大于等于啊,就amount是有可能是零的,对吧?好,所以把这个加进来之后,我们这个就没有什么问题了。
07:06
但是大家如果细看的话,刚才他这一个函数其实是有返回值的,它会return一个布尔型的返回值,这个是方便什么呢。就是方便别人调用的时候,能够看清楚这一个到底转账是成功了还是没有,所以有一个返回值判断,那大家充值的时候,或者说是就是第三方接口支付平台,大家就可以利用这个返回值来做校验,要不然的话,这边执行完了什么消息都没有,那别人也拿不到一个凭证啊,所以说真正的实际考虑的时候,一般都会加上一个返回值,所以我们在这里return true给大家看到,这就是这边的一个实现。呃,这个实现其实呃,相当于是这个以太坊官方的一个实现啊,大家可以看到上面网址是以太坊的官方网站的下面一个token的一个例子。
08:11
所以大家可以看到,呃,当然了,它的实现这里还加了一个名字啊,就是返回的时候。返回的时候告诉调用者success是true还是false,这样的话,我们调者一看到success这个字段后面跟着true,那就知道这个调用是成功的,所以这个发币就是正常发出去的。这就是。已经很接近现实的一种实现,在这种实线下,大家可以看到,首先我们前面的那一个靠影在设计的时候是有问题的,因为有一个名特,它可以无限的造币,而且随意的转币,这个啊,当然就是说如果B权是他的话,他想给谁转,这个当然是可以的,但是他可以无限的造币,这个一般在我们现实当中明显这个就是不合理的,所以针对这样的一个不合理呢,我们就需要。
09:10
把整个这个币种的总量值限定下来,不要无限的发,那总量值在什么地方限限定呢?我们也可以,其实还有另外一种方法啊,就有一些老的币种,它有可能它用的是更原始的方法,就是我们在这里直接限定一个叫。这样,Total supply。直接限定一个,然后这个total supply,它通过。我们一开始的这个调用去把这个写死,或者是通过后面有一个set total supply的方法要求这个,呃,我们的这个调用者去把它下,就是重新的重置一下,但这个可能就会有问题,就是你留下了这个接口的话,那就是你一开始发的币之后还有可能变。
10:07
所以说大家可以看到现在的最佳实践方案,其实就是都不要这些复杂的定义,我们直接在constructor里边把这个输入,然后把这个给到message centers就可以了,所以就是这样的一种实现方案。好,那我们接下来就多说一点,就是给大家看一看这个吧,刚才的这个简单的实现方案,它涵盖的这个思想。就相当于是我们现在经常用到的大多数在以太网上发行的代币的一个基本的思想,那这些思想提炼出来,然后在完善之后,就形成了一个标准规范,这个标准规范就是我们经常所说的ERC20 erc20代币合约,它到底是一个什么样的规范呢?我们可以带着大家来看一下啊,就尽管我们前面写的这两个代币,两种模式的代币都非常非常简单,但是ERC20的代币可能相对来讲就有一点有一点点麻烦啊,我们过一下呃,大家可以看到前面的版本,我们先不要管。
11:22
后边它首先是定义了一个interface。这是什么意思呢?哦,接口对这个我们还没有讲啊,但是大家可以直观的去去想,就是,呃,这个接口应该就是说,就像其他语言里面的接口一样,它先定义这个接口里面会定义接口方法。然后如果要是有别的合约实现了这个接口的话,那肯定就会去就真正的实现它里边的方法对吧?那我们看一下这个接口是要干什么,它叫token receive。Recipient,这个应该就是就是说token的接受人对吧,接收者,然后它里边说这个接口里边必须得有一个方法是receive approval,也就是说呃,你要对这个接收有一个approval应该叫什么,应该叫批准还是叫叫准许对吧?对对批准这样的一个一个概念啊,具体如果咱们不知道他到底是要做什么的话,我们先不管,我们看下面吧,下面这个就容易理解了,我们看con contract token ec20,这明显这就是主要的这个合约内容了,对吧,我们看一下。
12:40
下面首先一上来就定义了一个string。Public。然后public symbol。这两个是什么东西啊。这对其实就是笔名和它的简简写的那个标志,所以呃,一般情况下,就比如说如果是假如说啊BTC,如果要是就比特币在在这个以太坊上也构建一个类似的EC20的代币的话,那就应该是这里name就填一个bit Co,然后symbol就填一个BTC。
13:18
基本上就是这样的一个状况。呃,可惜我们现在是看不到us的那个代币合约了啊。我们看接下来还有一个东西,它定义的叫做UNIT8PUBLIC decimal等于18,这个是什么东西呢?这相当于是定义了它货币的子货币的一个精度,所以这个就相当于直观理解就是。呃,可以认为是它的小数位对小数点的位数,大家可以看到啊,它这个18DECIM is就是它,它这是最强烈推荐的一个默认值,呃,就是最好避免去去修改它这个我可以跟大家分享一个就是。
14:05
嗯,就是有一些人可能不知道,一开始不知道这个是什么意思,所以部署的代币合约经常就自己自作聪明的把这个改了,然后他觉得这个默认值给一个18,很奇怪的一个样子,然后看着前面这个又像是一个一个数字化的一个什么东西,对吧,然后就自作聪明把它置顶,越小越好嘛,肯定。至零了之后的一个结果就是什么呢?就发现自己发出来的代币只有整数,没有小数,为什么会这样,等一下我们看看到后面就就知道了啊。呃,我们看下面就是它这里直接定义了一个total supply,这就是它最重要的四个状态变量,Name symbol啊,Decim decim是直接附了初值,而且不改的,然后还有一个特的好,接下来就是看它的其他的一些数据结构,那我们看到这个就很熟悉了,我们看到一个mapping,从地址到U256的一个mapping,对吧,这跟我们定义的完全一样啊,当然它是叫balance,呃,就像我们后来看到的那个标准子货币一样,然后接下来它还定义了一个东西,这个东西叫做allowance,这个应该就是就什么呢?
15:28
准许许可,那所以他是想表达一个什么东西呢。就是在这个ERC20的代币合约里边,它不光是。你可以给别人转,你还可以允许别人用你的名义给别人转,也就是说,你相当于你给别人授权了一个额度。所以这里要记录的是你给别人的授权额度,所以我们看一下他的数据结构,首先他也是个一个mapping,每个人都有可能对别人有一个授权的额度,对吧?就是首先是一个address,每个人的账户,每个人的地址都对应着一个,对应着一个什么value呢?Value又是一个mapping,这是为什么?
16:17
是因为在我们这个系统里边,那就是每个人都有可能对剩下的所有人。有一个授权对吧,所以说他的这个账户address下面也要存着一个表,这个表就是对于其他所有人的一个授权,授权的表。那这个表呢,我们还是用一个mapping来保存它的这个映射关系。那这个mapping的内容那就是。里边其他的每一个人的地址对应着给他们的授权额度,对,稍微有点绕啊,就是这个就是层级稍微多了一点,数据结构稍微复杂一点,大家看能不能绕过来,呃,然后下面就是我们也是算是比较熟悉,至少是见过的东西,对吧,定义了一个事件,这个叫transfer,那我们能想到了,这就是转账的时候,我就触发一个这样的事件,后面也是一样的啊,它就是from to,这个index大家先不用管啊,这就是他要他要去做一个这个,呃,就是检索,给一个事件的检索。
17:26
From to value3个标准值。然后下面我们又看到他还有一个event,定义了一个approval event,就是谁给谁授权了之后,我们也要记下来。首先记一个owner,然后记一个spend,然后记一个value,就是说就是谁拥有这样的一个授权,然后谁给他的授权,到时候是谁花钱对吧,然后还有一个白领。最后还定义了一个事件,叫倍。
18:00
Burn是燃烧的意思对吧,所以那从字面上来讲,那就应该是他好像会想要去烧钱的意思,那应该就是要销毁它的一些代币,所以大家看EC20里边,它其实是定义了这个代币的销毁机制的。尽管可能有些,呃,ICO的这些小小币种,他根本就根本就不会用这个机制啊,当然有很多大币种他是会用的。比如说像BB,它就是有这个代币销毁机制,经常就会去调这个方法,所以大家感兴趣的话,就可以看那个BN币代币合约上面,它调用的那些交易,有没有调过这个泵。呃,那么这个要传进来的就是首先就是from,你去你去燃烧那个哪个地址的这个代币,这个钱,然后燃烧多少。啊,这就是它基本的一些数据的定义,那接下来我们可以看到啊,这个还是老版的啊,所以它的大家还记得它的合约名称吧,就叫token erc20,所以它这里又定义了一个function token erc20,那这就是我们的构造函数了,所以这就是我们的constructor,它在创建的时候,大家看要传进来什么参数,它这个写法是这样的一个标准,大家也可以学习他这样的标准就是它把参数一个一个列在这里,然后后面public下面是函数题。
19:33
它的参数一个是initial supply。就是我们前面说过的传进去的总数。还有一个叫token name。这个也是可以定的,还有一个叫token symbol,他为什么要把这些全定义成一个。就是constructor里面的参数呢。创建合约的时候就已经定的是吧。
20:00
那那为什么不直接把这些直接就在前面写死呢?比如说这里不就已经有了吗,Name symbol。就是为什么不像这个DEC这个一样写死呢。因为如果我们在这里写死的话,那这个合约每调用一次布出来的,就是创建出来的那个代币名字都是一样的,对吧。那别人如果要想发不同的币的话,就只有去硬改这个hard code的这个值,对吧,硬把它改了,重新再来补一遍,那这个就会有各种各样风险了,好像从技术的角度讲,觉得这种方法也会很很不安全,或者说很low,对吧,你去硬改别人的一个参数,这样其实是不推荐的,所以为什么他叫一个ERC20的协议,或者说标准的,就是说这里定义好的东西我们都不用改,我们直接调用它就可以。
21:13
调用的时候,我们再把这些东西传进来,那你给不同的token name,给不同的token symbol,我们就创建了不同的代。其实就是这样,在创建的时候,我们再指定这些东西,然后我们创建出来的代币实例就是一个完全不同的代币实例,而不用再去再去改里边的这些。具体的参数对吧,那大家其实在这个时候其实已经可以想象一下,就是我们要利用这个EC20的合约这个标准去创建代币,该该怎么利用呢。呃,这里可能就提到一点,就是呃面对对象,或者说就是其他的一些语言特性,就是solidity是允许继承的,因为我们认为呃合约contract就是类嘛,类当然就是继承是一个很很重要很很大的一个特性,所以它既允许去我们去调用接口,实现接口,也允许我们去继承一个父类,所以如果我们自己要利用这个。
22:28
代币合约的协议的话,那我们直接自己去继承一个。Token ec20就可以了。那继承了之后就会有它这些所有的参数属性,那然后我们继承的时候,我把把这些东西传进去,就可以实现自己的代币合约了,好,那下面我们看一下啊,下面其实就告诉了我们为什么这个DEC比较重要,大家可以看total supply是什么东西。他是。
23:00
我们前面定义好的这个初始的supply。乘以十后面这个两个心,这个代表的是对幂幂运算乘方,所以它是十的后边这么多次方,我们定义的decim是18,所以就是十的18次方,所以这个总数相当于是跟尾的那个定义是是一样的,对吧?就相当于我们给定我提供多少个以态,然后后边算出来total supply就变成了一个稳,相当于是这样的一个概念。所以最终其实这些都还是整形的。没有出现浮点型,因为大家知道浮点型容易出现精度缺失,对吧,精度做精度运算的时候容易出现错误,所以一般情况我们是要尽量避免浮点运算的。这里都是用整形。那如果有人要是愿意把这个写成零的话,那就那倒是也简单,就是相当于initial supply,就是total supply,但是它就是完全不可拆分的,它的对它的最小的。
24:13
呃,就是交易单位就是就是一,所以那那这样的币的话,可能就是怎么说呢,就是没有办法拆分去去做交易,那可能真的就会有比较大的问题吧,呃,你像如果要是说像以以太或者说比特币这样的比它如果定义的不可拆分,那我们大家去非得要买就得买一个比特币,那可能真买不起。那它的流动性可能就差太多太多了,对吧?好像下面就是我们前面实现的一样的东西,但它定义了total supply之后,把所有的total supply直接给到message send。Balance,它直接给定total supply全部由他来分配,那name就等于token name symbol就等于token symbol。
25:04
这两个都是我们前面定义好的状态变量,对吧?而这是在constructor里边传进来的参数,所以说这就是用传进来的参数直接付给了我们的状态变量。好,接下来我们再看一下这个。这个稍微有点有点复杂啊,我们好大,是不是想先休息一下。呃,那那大家先休息一下吧,剩下我们等一下,可能再重点看一下它的transfer,它的转账的过程,还有一个是他的approve approve的过程,就是授权的这个过程,最后还有一个就是它燃烧带B。呃。大家可以看到啊,这个真正实际应用的这个ERC20的协议,其实内容还是蛮多的,所以这就是我们自己实现一个代币很简单,但是如果要是出于安全性的考虑,出于标准性的这种协议规范的考虑,那可能还要加很多很多东西,很多很多内容。
我来说两句