00:00
到目前为止,大家就会发现主体的一些功能都已经完成了,都已经搞定了,但是我们其实还留下了一个,大家可以认为是留下了一个问题,也可以说是留下了一个要解决的东西,对吧?大家会发现我们真正finalize之后,这里面我们变空白了。为什么会空白呢?那我们其实提到在index.js里边,在这个detail,这是product detail就是产品详情页对吧,我们刚才那个页面是产品详情页里边,我们定义了它的显示哪个模块的这个规则,对吧?所以大家会发现我们要求假如说上来之后,我们是先判断这个P8的,P8是什么,是产品状态。Product status,呃,大家忘记的话,就随时回到我们这个主合约里边,看这一个get product返回的是什么对吧?P8就是我们倒数第二个。是status,所以我们这里边先要判断status是不是等于一,那一大家还记得吗?是这里一。
01:09
大家记得这个一代表的是so的对不对?我们定义的枚举类型,所以假如说我们已经是卖出去的状态的话,我们这里是不是就显示一个状态,你应该是卖出去了,然后假如等于二的话,没卖出去的话,我们显示一个它没卖出去之后,最再往后的这个else才是产品status等于零的状态,对吧?那如果要是等于零的话,就说明它还是open的状态,还没有结束拍卖。那没结束拍卖就又有三种情况,假如说还在竞拍结束时时间之内,我们就是显示B被竞拍,如果已经结束了之后,而且还在结束之后的十分钟之内,我们可以结时报价,那我们这里是写死了对吧,大家可以把这个再再改一改,另外就是说如果要已经结束十分钟之后,我们就显示final。
02:03
那如果我们finalize之后,那么大家知道这个finalize这个这个步骤是不是在合约里边我们已经定义好了,它会更改我们的合约里边对应的那个产品状态啊,我们会把这个status制成so的,对不对?或者是假如没有人拍卖的话,制成on sold,所以我们一旦点了那个finalize按钮之后,我们就会发现。他一定会跳到前两步来,对不对,那这前两步里边我们是在HTMMML里边要拿到ID叫做product status的那个do节点,但是这个节点我们在这这里边现在还没有定义,对不对啊,所以大家就会发现这里面什么东西都没有对吧?那如果我们定义了之后,按道理它至少会显示我们这里边的一句话对不对,Product so,或者是product not sold,对吧?好,那么我们这节课接下来就是要把我们最后剩下的这一部分彻底的把它完善起来。
03:02
好,那么呃,我们看一下,就是我们进行到课件的哪一步啊,大家会发现我们现在其实就只剩下这个,呃,前面这一部分都已经做完了,对不对,只剩下最后一部分就是释放资金。啊,大家会想到我们如果要是说这里已经finalize结束之后,然后他这个产品确实是已经卖出去的状态的话,那我们还有两个步骤。没有去处理,没有在页面上能够体现,就是什么呢?我们不是创建了一个托管合约吗?托管合约里边他是要做什么呢?不是说钱存进去就完了,对吧?是最后我们达到了2/3同意的时候,要把它释放给买家或者卖家,对吧?这个款是要打给买家或者卖家的,所以说在这个阶段我们还是有用户应该在我们页面上去做交互的,什么交互呢?那就是只要是我们合约里边参与的三个人,买家、卖家或者是仲裁人,他应该就能够点两个按钮。
04:09
要不他说我去,我提议可以把这个我同意可以把这个钱释放给买家,对吧,直接呃释释放给买家的话,就相当于是退款了,对吧,退退回给买家,或者他可以点击一个按钮说我同意把这个钱要支付给卖家,所以我们接下来还有一个事情要做,就是。把这个已经这个产品已经卖出去的情况下。那我们可能不仅仅是简单的显示一个他的SL说他卖出去了。那我们还得显示两个按钮,让他可以去点对吧,让他可以去释放这个资金,好那么我们接下来看一下,就是在我们这个课件里边怎么去写的,大家会看到释放资金这一部分,我们又牵扯到几部分的内容。那我们在做这个区块链,就是以太坊上的区块链开发,大家开发D的时候,考虑一个功能的时候,首先考虑什么,首先考虑我们的后台,也就是合约里边有没有这个功能,对吧?首先是合约,所以大家会想到我们的合约里边是不是已经实现了释放资金的这个功能呢?
05:20
大家回忆一下我们的astro这个合约。其实我们已经实现了,对不对?大家回顾一下我们在这个合约里面干了什么事情呢?首先我们创建了一个constructor这个构造函数,这个构造函数就把我们的钱直接存进来,然后初始化了信息,对吧?那剩下的两个主要的函数是不是就是在做释放资金的这件事情啊,啊,昨天我们其实就是上午,昨天上午我们很大一部分经历其实在做这个事情,对吧?那大家再来回顾一下我们昨天写的这两个函数,这两个函数它是非常类似的,一个叫做释放资金给卖家。那也就是说支付对吧,这个钱可以支付给卖家了,那2/3的人同意,也就是说我们这个塞拜尔和这个阿BI特仲裁人三个里边有两个同意的话,我们就把这个钱转给卖家,那有两个人同意,这个数据我们怎么表示呢?大家记得我们在里边是用一个mapping来表示的,对吧?这是一个地址到一个布尔类型的一个映射,那这里边大家就会想到地址肯定就是我们这三个参与人的地址了,然后这个布尔类型呢,那就是出或者false,它表示什么呢?默认它都应该是false。
06:36
就表示我还没同意呢,对吧,那如果说我同意点了那个按钮的时候,是不是它对应的那一个地址,就应该相对应的那个值改成处啊,就表示我同意释放了对吧?那所以我们定义两种情况,因为我们这里有两种情况,一种是release amount,这表示释放这个东西给到卖家,对吧,另外一个就是refund,就是回款退回给买家,那这两个都代表我们三个人是否同意这样的一个数量,大家就又会想到。
07:07
我们的这个address是不是,呃到这个罐类型的这个映射,我们没办法去便利啊。所以我们现在想要知道是不是达到2/3,好像还有点难,对吧?啊,这个我们每次都便利一下,这个在以太坊里边便利一个mapping是不可能的,所以我们还要定义另外一个计数器,就是我们一旦把一个从false变成true,我们计数器加一对吧,所以大家会想到这个release release count,或者这个fund count,那它最高就是三。到达二的时候,大于等于二的时候,我们就应该真正把这个钱转出去了啊,这就是我们一开始这个我们所定义的数据类型的一个考量,那在具体我们操作的时候,大家就应该能够想到,我们应该是网页上有一个按钮,一点这个按钮我就应该调到,比方说我现在要释放给卖家对吧,把这个钱打给卖家了,那我就应该掉release month to sell对吧,然后我就会判断你首先是不是我三个参与人之一,S bear a abi对吧?如果不是的话,那你这个就肯定不能做这个操作,那在接下来大家就会发现,我们肯定就要判断你的这个操作人是不是。
08:24
这里边这个release,我们那个mapping里边,它已经变成true了呢,已经变成true,我们就不应该再去操作了,对吧,如果没变成true,它还是false,那我们就可以把它变成true,表示我们同意有一个人同意他去释放了。然后把我们的这个count计数器加一对不对啊,所以后面这是释放一个这个事件对吧,触发一个事件,那接下来大家会注意,我们既然有了这个count增加的。这个过程接下来我们就应该相对应的有一个判断,看看这个count是不是已经大于等于二了,对吧?如果要大于等于二,我们接下来直接就把这个钱转给我们的卖家啊,其实就是这样的一个过程,对吧?啊,那当然了,就是我们这里还有一个标志位,这个标志位如果是处的话,就表示我们这个资金已经转走了,接下来你别想再动这个钱了,对吧,已经没了,所以大家会发现我们一开始就要求你必须这个钱是没转走的时候才能做下面操作,如果转走的话,你这个就呃,完全没用了,对吧,就不要再去想了,所以这是我们把钱释放给卖家,那释放如果要转给买家,回款给买家也是一样的操作,对吧?呃,那这个地方大家这个逻辑都已经是梳理清楚的,那我们今天要想去具体实现的时候。
09:43
首先我们就应该想到。我们想的是在网页上点一个按钮,然后就去调这个合约对不对,但是大家要注意,我们昨天的这个设计里边创建合约是在我们主合约这个1STORE里面去创建的,对不对,然后把它的地址就存在那儿了,那我们的网页。
10:06
如果要想去直接调这个合约的话,是不是我们调不到,因为不是我们直接发布到,就是我们的这个用户直接发布到这个区块链上去的,对吧,而是。大家知道在我们发布主合约的时候,我们在trouble里边是不是直接用了trouble migrate把它发布上去的,所以travel是帮知道这个合约的,对吧,帮我们把它管理起来的,那我们在这一个每一次生成这一个s as pro托管合约的时候,我们是不是并没有告诉他错是在我们这个主合约里边,它自己生成的管理起来了,对吧,把那个地址记下来了,那所以我们如果在trouble里边想要去直接找他,我们在WEB3里面想要去直接调他,是不是我们调不到啊?因为大家能想到,我们要调这个合约,你至少得知道地址对不对,但这个地址我们只有在这个合约里边存了。
11:03
窗口里面是不知道的,所以我们不能像之前调这个合约一样,很简单的去直接调调大家就会想到,那我们怎么办呢?有些同学可能想到,首先呃,最简单的一个方法,可能大家想到我这里边不是能够拿他的地址嘛,对吧,已经存了,我这里面有个方法能够拿到这个地址,那我们是不是可以,呃,就是在我们的网页里边调的时候,先调他的这个获取地址的这个合约。然后把它拿到地址之后,我们再在网页里边用WEB3去写对吧?那大家还记得之前我们那个已已知一个地址的时候,怎么样去创建合约实例吗?拿到它的API对吧?然后我们调它的呃,这个web3.contract,然后Eth.contract we3点contract.at一个地址,然后就能用这个合约对象了,对不对啊,大家可以想到这是我们之前学过的这种调用方法,我们就能调用这个as pro合约了,但是大家会不会觉得这个有点麻烦啊,我们脱离了trouble的管理框架对吧?然后自己又要去拿它的编译好的那个abi,然后又要去艾特他的地址,这个就很麻烦。
12:19
那我们是不是就有另外一种考量呢?他会想到我们昨天其实在这个主合约里边,是不是已经调用过我们创建出来的那个托管合约啊,我们调用的方式是什么呢?就是在这里边能拿到他的地址,然后直接点他的方法是不是就可以掉了。诶,那我们是不是可以想到,我们可以用主合约作为我们的入口去调用,对不对,所以我们用户所有的操作,我们点击那个按钮之后发起的交易,我们直接去调主合约的函数是不是就可以啊,那同样大家就会想到我们是不是在主合约这里应该去定义一个我们想要调用的方式啊。
13:02
呃,那首先大家就会想到我要去release,我的这个金额给到卖家,给到saler的时候,我同样在主合约里边定义这样的一个方法,对吧?Release amount to seller,所以这就主合约里边变成了我们的一个入口,对不对?那这个传过来的参数应该是什么呢?那大家肯定知道我主合约里边什么都不知道,我就知道你的这个产品的ID对不对,我们网页上这个ID是能拿到的,那别的信息我都不管,我直接就传过来就完了,所以这应该是一个public类型,对吧?然后后边return,呃,啊,没有说return对吧?我们后边直接去定义它要做什么操作,那大家会想到我们是不是就应该跟上面这个查询这个s as pro infer一样的操作对不对?我们是不是在主合约里边不需要做具体的操作,我们直接调as pro里面的操作就可以了,对吧,所以我们还是一样的,是不是把这个。
14:07
Product as pro里边的对应的那个地址拿出来啊,所以是product as,这是我们定义的那个mapping,存了每一个托管合约的地址的,根据它的ID拿出来,然后强制类型转换,前面加上s pro,这是不是就拿到他的合约对象了,然后我们就可以直接调它的方法了,对吧?这个时候调诶外面啊,调什么方法呢?我们是不是在as里面已经定义好了,对,所以这里就已经有release amount to sell了,对吧?所以我们直接调用这个方法就完了,所以大家会发现,诶,我们通过这样的方式就解决了我们前面。感觉好像很棘手的那个问题,对吧?我们想要调as pro这个合约,但是呢,我们在外面又没有办法用叉管理起他的地址来,我们没有办法直接拿到地址,只能从主合约这里去拿,那拿到之后我们又不想那么烦的脱离窗口框架,我们还要自己去拿到它API,再去创建它的这个具体的合约对象,合约实例,对吧?那么我们就干脆学习我们上面的这个方法,直接。
15:17
学习我们昨天实现的这个as pro info这个方法,对吧,就把主合约当成我们的调用入口,然后他拿到对应的这个合约实例之后,直接调用我们这边SQ合约里边的方法。来再再回顾一下,再看一看这个调用方式,对吧,这样的话就实现了我们这样一个功能,好,那么大家肯定可以想到,同样非常类似,我们是不是有了这个release amount to sellar,是不是这边还有一个是refund amount To Bearer啊对吧,那这边同样我们定义主合约这边的一个refund amount To Buyer,把它回款给买家,同样它是一个public类型,我们就把它return as pro给到谁呢?同样里边哦,小写啊,Product astro。
16:13
里边我们还是拿到它的对应的地址,然后直接调用refund mount To Buy这个函数,哎,这就搞定了对吧?所以大家会看到,呃,呃,但是你注意啊,我们不应该return了,对不对?因为我们这个没有返回值对吧?我们不应该直接照着抄上面啊,大家要搞清楚这个到底是要获取信息要有return,还是说我们只是调用一个方法做一个操作就可以了,对吧?这里我们只做操作,所以不需要return,好,那么这里我们就已经把这个合约调用的这一部分实现了,但是这里大家是不是会发现好像还有一个问题,有同学发现我们这种方式有什么问题吗?啊,我们这里调用的时候这里没参数对吧?大家会看到我们as pro这里定义的这个方法是没参数的。
17:07
那这个方法里面我们会做什么事情呢?我们会去判断,首先这个标志位是不是已经变成变成处了,如果已经释放掉,那就别做了,对吧?然后我们判断当前的调用人是不是买家卖家和这个仲裁人里边的一个,那这里边我们直接用的就是me send,对吧?那这里大家是不是会发现有点问题啊。我们本来想的是我们在外面直接点直接去调用,那这个mesger center就应该是我们那个调用人对吧?大家用ma mask去去发起这笔交易的话,Ma mask的那个count count0就应该是这个三,但是现在不一样了,现在我们的ma mask那边发起的交易是不是会传到这边来啊,我们是在这边用合约又调用的这个合约,那大家会发现这个发起的这个调用就不是交易了,就是我们内部的合约的消息,对吧?那到了这边之后,这个me center应该是谁啊?
18:10
这就变成了我们这边的s SE store这个合约,对合约的地址对不对,这是我们合约调用的另外一个合约,所以这一这个地方大家就要注意,那我们就不能简单的去写message standard了,对吧?那大家会想到我们这里是不是还得拿到之前的那个调用者啊?对,这个就有问题了,大家就会想到我们怎么才能拿到之前的调用者呢?对,两种方法,一种大家可能想到我们之前说过一种方式,我们可以用那个叫做代理调用,对吧,Delicate call,用这种方式我们就相当于把这边当成了一个库,把那边当成了一个库函数,对吧?那这边调用过去的时候还传递的是之前的message send啊,这是我们之前讲过的一种方法,但是当时我们还说过就是deleate delegate delegate call啊,啊,这个有点难拼,这一个方法其实是我们在solidate里边比较底层的一种调用方式,对吧?就是我们当时说过call delegate call,还有setting call这几种直接的call,这种方法其实都很底层。
19:22
我们在有其他方法的时候,呃,尽量不用,不要用这么底层的方法去去处理事情,对吧?除非我们没招了,最后一招用这些方法,那我们就会想到其实还有更简单的一种方式,我们是不是直接当成参数给他传过去就完了呀,那我们在这边是不是就可以拿到了,所以我们这里就给这个不要不传不传参,我们再定义另外一个参数。对,我们是不是有一个address类型,我们定义一个调用者调用定义一个color,对吧?然后我们这里的messages sender是不是就应该都变成color啊,啊,我们要判断coller等于celler,或者coller等于buyer,或者coer等于abi,所以大家会看到我们大家如果细心的话,对比这个课件会发现我们之前实现跟课件里面不一样,课件里面其实用的这种方式对吧?所以我们现在还是改过来,因为之前我们熟悉的是me send这种方式,现在我们就知道为什么课件里面要这么写了。
20:30
下面还有message center吗?没了是吧,好,我们这个全局替换一下吧,点三好,我们上面这里还有对吧。它的这个有全局替换的这个函数吧,Replace对吧,我们把它replace成po对吧。好没了对吧,然后我们在这里同样还是定义一个address类型的。
21:03
对,好,现在应该没有错了吧。这真是好慢啊,好,那么大家会发现我们现在就理解了,课件里面为什么要那么写,所以这个也就是呃,我比较强调强调跟大家说的,大家如果直接抄一遍的话,其实简单对吧?但是我们应该多去想一想,他为什么跟我们之前的写法不一样呢?啊,为什么我们之前熟悉的就是你直接message send就完了嘛,这边怎么奇奇怪怪的还要把这个call传进来,因为我们这里是用这个主合约作为入口合约调用合约,对吧?那如果我们不想用那种代理调代理调用的方式的话,代理给的call的话,那么我们就得把它传进去,所以我们这边是不是也得传一个参数啊,那这边传什么参数?这边就应该是mesger center了,对吧,大家应该能想到这里的mes send是我们真正的这个调用合约的发起交易的那个人,而到了那边mes center就变成了这边的emer store这个合约,对吧?所以我们把这个传过去就可以把我们的调用人保存下来了,所以大家会发现我们更改之后,现在的两个合约作为我们的后台是这样啊,所以大家会发现就是我们这个这个代码其实很简单,就加了这么。
22:26
就加了这么四行对吧?呃,但是其实就是这个过程当中,大家要梳理清楚我们为什么这么做,然后我们为什么要把这个me center要传过去。
我来说两句