00:00
好,接下来我们就来讲这个投票合约,这就是我们准备要实现的很关键的一个东西了,好,那么我们直接在这这里来码一下吧的。好,呃,我这里边为了方便起见,就直接在之前我们这个投票合约里面去改了啊,好,那同样大家进来之后prama solidity,对吧?呃,这个我们当前给的好像都是4.1几对吧,这个不重要啊,4.1817都可以,好,那么接下来我们定义一个contract,叫做voting,这个大家都很熟悉的步骤,接下来大家注意,我们首先应该去定义一个,之前的话我们没有定义投票人这样一个概念,对吧?因为之前我们就是一人一票嘛,你用地址直接去代表就好了,那现在的话可能我们就得复杂一点,因为每一个投票人他的手里边有的token不一样,这是最基本的一个想法,那我们首先得把这个定义出来,所以我们一上来。
01:15
就先定义一个structure叫做voter,这就是我们基本的一个一个数据结构,对吧?那首先我们还是把它的地址先记一下吧,呃,Address,我们就叫vote address吧。好,这首先我们把它的还是跟我们之前一样,之前我们是按地址来区分人,我们现在还是把地址先记进来,然后接下来呢,就应该能够想到,首先我们应该有一个它的token token数量,对吧,Token。应该叫什么token啊,我就我就随便写一个就叫token number吧,大家可以自己定义它的名字啊,好,那么接下来大家应该还能够想到我每个人除了手里边有的token,拿到token之后还得去投票,那投票我给每个人投票,其实结果是不就之前我是只能投一票投给一个人,对吧?那现在的话我是可以给每个人投票,而且还能投不同的票数,所以这个其实也是应该记录下来的,所以我们前面说了,我们用一个unit数组来记录给每一个呃候选人投出去的票数,对吧?那我们这里就叫什么吧,叫token。
02:34
Tokens,然后vote for candidate candidates,好,这是我们的这样一个vote的一个,呃,一个一个数据类型对吧?好,那接下来大家看一下,呃,我们接下来应该还得定义,大家能想到还得定义什么东西呢?
03:02
呃,我们还得定义,就是我们token相关的一些东西,对不对,就是我们一开始要发行token的话,那你肯定得知道我到底要发行多少啊,对,然后我现在合约里边还有多少token啊,所以这些东西我们也是要定义出来的,那you public,这ton肯定是可以公开的,对吧?比如说我们的total tokens,这就相当于一个total supply对吧?在EC20里边的一个total supply,然后我们定一个UN public,我们那个叫token balance,对吧?Balance balance balance不行,好,呃,然后我们定义了一个总数,然后定义了一个余额之后,大家应该还能够想到,我们如果用户要去买这个ton的话,他还得有一个单价,对吧?对,这个我们也得定。
04:03
比出来这个我们就还是定义成整形吧,因为我们的单价可以都用这个,都用尾来表示对吧?这个其实不需要去去定义,这个用大整数就可以了,Token price,好,这三个已经定义出来之后,我们整个token的这个啊,当然大家也可以去觉得这三个如果比较就是定义这三个数比较麻烦的话,也可以定义一个叫做token的结构体,对吧?直接把它放在一起也是可以的,我们这这里是分开去定义了,大家可以自自己发挥,去构建自己的这个数据结构,好那接下来除了我们的这个token之外,呃,大家记得一开始我们还得有一个候选人列表,对吧,初始化的时候得写进去,好,那么我们候选人列表这个数据结构我们定义成BEST32吧,三二啊,好,BASE32,这是一个三二的数组,好。
05:03
那接下来我们把这个定义成叫candidate candidate list,我们现在已经定义了vote投票人,定义了token,定义了就是token发行多少,还有他的余额,还有它的单价,然后我们还定义了呃,我们的候选人列表。那现在我们还缺什么呢?应该还缺一些对应关系,对吧?谁给谁投了多少票,然后每个人得了多少票,所以我们在这里定义一个mapping。呃,这个mapping应该是从候选人到一个他得票数的一个mapping,对吧?这个大家应该能想到,那就是BESTS32到U的一个数据类型,一个map mapping,然后public,呃,上面我们这个看见的例子,大家应该想到也是public,对吧?这个肯定也是可以去公开去查询的,好,那么我们这里定义的这一个mapping,我们就叫做,呃,这应该是candidate,每个人接收到的投票数,对吧?那么我们就叫load。
06:19
哎呀,这个不应该叫what for,这个有点有点跟后面的方法重了,对吧,我们这个教案里边是怎么写的,怎么命名的,这个好,这个比较明确啊,这个叫votes received,这个就明确一点,对吧,每个人接收到的我们就用这个名字吧,Received,有时候大家这个就是命名的话,可能也得注意一点,就是命名的好的话,自己后面的这个代码逻辑就不会乱,因为知道它到底是什么东西嘛,要不然的话自己写着写着就乱了啊啊另外刚刚大家瞄了一眼就发现还有一个信息,还是就是为了方便我们做查询,是把这个地址,每个人的地址跟我们的这个voter的数据类型是做了一个mapping映射的,所以也就是说我们可以根据这个。
07:14
因为大家看我们在voter这个类型里边,大家是没有办法去根据当前的这个voter address直接查到这个voter对象的,对吧?所以我们必须还得用一个映射来保存这样一个对应关系,尽管这里好像看起来有点冗余了,对吧?所以大家注意一下,我们这里再用一个mapping去存储一下每个人的地址到water的这个映射关系,那这个关系我们就叫做water infer吧。好,现在我们所有的这个数据结构其实就都已经定义出来了,对吧?那接下来我们就是合约里边的方法了,合约里边的函数首先肯定就是constructor了,对吧,Constructor。
08:04
好,那这个constructor大家会想到我们首先要传入哪几个参数呢?我们看一下上面定义的这些东西,哪些是一开始就得确定的。这个头tokens是不是一开始就得确定啊,对,所以我们肯定能想到,这个是我们一开始就应该给定的所有的一个上限,对吧?好,那么我们就u in一个total supply,好,然后大家应该能想到我们下边的这个单价是不是也应该指定啊,你后边不应该变来变去对吧?好,所以我们再定义一个UN price吧。Price,好,然后还应该想到我们的这个candidate list,这个也是初始化的时候就应该知道了,对吧,给哪些人投票,所以投票人列表这个U,哎,这个不是u in的是吧,BEST32啊,BE2,那么这样一个列表,我们把candidate我们叫names吧,传一个数组,就是传所有候选人的名单,作为数组传进来。
09:23
好,那么现在大家就可以想到,诶,大家注意我们这里没有给他的这一个函数类型对吧?默认肯定都是public,所以养成好习惯,每次写完一个函数定义的时候,后面跟上它的这个可见性,还有其他的一些类型,好呃,那么接下来大家想一下,我们这里定义了这些几个参数之后,带进来的参数我们肯定要付给状态变量对吧?那首先这个total supply,我们肯定就是给total token,诶,所以怎么没有自动补全啊,FLY给到total token,然后我们第二个参数。
10:06
肯定就是给到我们的total,呃,我们的token price对吧?好,那接下来candidate names肯定就是给到candidate list,这个都没什么问题啊,大家candidate names,好,那么大家注意一下,我们一开始上面的这个状态变量里面,除了这个votes received和vote infer,这个肯定一开始不需要初始化,上面的这些东西是不是都需要初始化呀?那大家看到我们还有一个没有初始化,还有一个token balance,这是我们定义的token的余额,对吧?合约里面还剩下多少token?那大家会发现,一开始我们是不是所有的都应该在余额里边啊,对,所以我们加一句啊,Balance,现在终于有这个提示了啊,就等于total supply,好,所以我们可以把这两个都附进来,然后我们现在的状态变量就都已经有了初值了,这是我们的这个构造函数。
11:19
接下来大家会想到我们接下来会会有一个什么动作呢?每个人一上来之后,应该先要去买这个我们的token,对吧?所以我们定义一个function叫做BY,或者大家想想叫的更明确一点,叫by token也可以,对吧?那么BY的时候大家想一下它应该要传进什么参数呢?呃,我们看一下这边的实线,它是不是。哦,这里是没有传参的,所以大家可以想到这里边我们应该有两种思路,一种是如果不传参的话,我就默认发多少以太来,我就给你把这个呃以太全买了token,对吧,这是一种想法。另外还有一种想法是,就是我传递一个参数过来,我传的这些以太是就是按照我要买的这个数量来买,剩下的以态你还得退给我,如果说不够的话,那是能买多少买多少,那样的实现可能就稍微复杂一点,对吧?所以大家看我们这里就先用一个简单的实现,大家如果自己想把它扩充的话,那可以扩充成一个,就我们刚才说的那种需求,就是我可以传一个我要买多少token,你自动给我做判断,我的给的以太能买多少,能买多少就买多少,然后最多就买这么多,剩下的你给我退回来,那这个可能。
12:56
实现就稍微复杂一点啊,我们这里就是只是一个简单实现了,所以大家会看到我们就不给这个传参了,所以就只要带着以态过来就可以了,对吧?那既然你要能带以太过来,它的这个数据类型得是什么呀?对得是payable,刚才大家看到了payable对吧?Payable后面当然public你得能从外边调用,那这个会不会有一个呃,一个返回值呢?
13:25
看这里好像是给定了一个返回值是吧,对,所以这里是把我们你直接传进来的,以态我就直接给你去按照这个数去买票,然后我把。Tokens To Buy,我把你真正买到的这个token的数量,然后返回给你,所以是这样的一个处理逻辑对吧?也就是说你我们在前前端其实是能拿到这边的一个返回值,所以是知道自己这一趟交易是到底买了多少token,这个也是比较合理的一种显示的模式啊。好,那么我们就照着这个来写吧,买了多少token,当然就是一个returns,一个U,对吧?好,那么接下来来看,我们肯定就是会定义一个呃,要买多少对吧?刚才的定义叫tokens To Buy对吧?就叫这个名吧,这个名还是起的比较直观,那tokens To Buy应该是等于多少呢?我们肯定就会想到是message.value用来买对吧,那用来买的时候,它这个value到底能买多少token呢?是不是得除以我们。
14:41
的单价,所以在这里去除以token price,好,那么这就是我们能够买到的这个数量,那当然这里边你能够买到的数量肯定不能比我们的总数还多,对吧?所以我要写一个require tokens To Buy要小于等于大家说这个我是提供的这个total token呢,还是token balance,对,应该是剩下的,对吧?肯定不是说总量是,而是我们现在剩下多少,你最多就能买这么多,好,那接下来我们都已经有了这个要买多少之后我们是不是就应该给它加上我们的数量了,对吧?所以大家可以看到,呃,那这里其实大家看你如果已经买了这个。
15:41
这个这个token的话,我其实应该是就相当于得构建一个对应的water这样一个结构体,去记录它所有的这些数据了,对吧,所以我们现在就相当于得有一个vote。呃,我们首先先在这个mapping里边先去记一笔,对吧,我们。
16:05
这个叫water infer。按照地址去选,所以是mes.ther对吧?Meger ther对应的这个vote,那么它的我们前面还有一个对不对?他的address先写,写进去就是message.ther对吧?那接下来下面它还有这个token number,我们同样把上面的这一串敲一遍,message.send.token number number,这个就应该等于我们刚才算出来的这个,呃,Token token To Buy token To Buy对吧,但是大家注意这里其实他之前有可能已经买过token了,有可能第二次买对吧,第二次买的时候我重新把它地址写一遍,这个这个倒无所谓,呃,我们前面这个写就写了,对吧,但是你下面肯定不能直接把之前的就给就给擦除掉,直接改。
17:09
还写,所以我们得加,所以是加等于token To Buy token To Buy好,那最后当然还有一个信息,Mesger their sender,他的tokens,好,这这个我们还没有去问呢,是吧?所以最后一个信息没有啊,这个我们不需要去做这个初始化,好那么关键的这两个信息,他买了之后,我们就应该都已经放进去了,对吧?那mon这边它的数量加上了,那大家注意,我们只要是涉及到这个钱或者说代币余额什么的,一个地方加另外一个地方一定得减,对不对?那V这边加了哪里得减呢?对,我们的那个balance对吧,叫token balance就得减,等于我们的token To Buy。
18:07
好,那么现在我们的这个方法就弄完了哦,上面我们还写了一个return对吧,那我们这里还得return一下,Return token To Buy,好,这就是我们的这个buy这个方法,所以大家可以看到这就是一个简单基本的一个实现,对吧?这个功能就做完了之后,我们的用户就相当于直接去可以去买我们这里提供的这个子货币,当然我们这个子货币非常的简陋了,但应该想到你如果要是有这个功能的话,我们下面应该还得有一个function式叫做transfer,对吧,你至少是一个货币嘛,那我至少应该得可以去transfer才可以,对吧?啊,这个当然是另外一回事了,这个也是一个public,我们先定义出来之后,我们再去实现。
我来说两句