在迅雷链开放平台看到了一个迅雷链足球竞猜的活动,基于迅雷链智能合约开发的足球竞猜应用。
从区块链的去中心化思维上来看,用智能合约实现足球竞猜能避免中心化博彩平台带来的暗箱操作、资金安全等因素,是一个很契合区块链方式的应用。但是具体还是要看合约的实现是否真的做到了竞猜的去中心化以及公开透明。
所以下面根据迅雷链足球竞猜活动页面公开的一些信息,及迅雷链开放平台的公开数据,抓取了一部分交易记录并分析源码来解读这个智能合约应用(顺便看下有没有漏洞)。 一、活动页面
从迅雷链足球竞猜活动页可以使用投注生成二维码,然后使用链克口袋扫码,收款账户地址即合约地址 0x2426ab3f531b0a93ef0ce45d73b40c0a8176d563
抓取一下比赛竞猜、历史竞猜、获奖记录的请求, https://worldcup.onethingcloud.com/api/game/query https://worldcup.onethingcloud.com/api/reward/list 根据迅雷链开放平台的文档可以看出这些接口并不是直接从合约层请求的数据,所以猜测合理的情况应该是经过一层后台服务将查询的数据封装输出到前端。
二、迅雷链开放平台 根据活动页展示的合约地址,可以从迅雷链开放平台展示的合约大厅里查到这个合约,以及合约的源码、bytecode、交易记录这些公开的信息。
1、源码分析 总共有3个contract,引入的zeppelin的SafeMath,一个Ownable权限控制合约,一个WorldCup主合约,结构很简单。
源码可以看出,`Ownable` 合约是使用构造函数传参的方式设置owner,而不是使用`msg.sender`的方式。这里应该是遵循迅雷链合约部署的限制在 zeppelin 的Ownable合约基础上做的修改。
关键合约 `WorldCup` 对权限的控制很严格,所有的非view函数(即涉及到写入和修改合约数据的函数),除了 `betGame` (投注)这个函数没有调用权限限制之外,其他的函数都要求 `onlyOwner` 才能执行。
2、关键函数实现 1)用户投注函数 betGame(uint8 gameIndex, GameRes betTo) 函数里本身的注释很轻松就能看懂整个逻辑,整个函数限定了调用投注函数的交易,value必须是2eth的链克,投注执行时的时间要在竞猜截止时间之前,然后在竞猜的结构体里记下用户投注数量。
2)提取竞猜奖金函数 withdraw(uint8 gameIndex, address _to) 提取竞猜奖金这种操作,如果按照合约安全实践推荐的方法,应该是由用户自己来pull,而不是由owner push的方式转账。但是这里使用的依然是owner push的方式。当然从产品角度理解,如果平台方公开数据并对应区块链交易记录的话,push方式应该更合理,毕竟参与投注的用户不用再掏交易手续费来领取奖金。 这里领取操作后将 `hasWithdraw` 标记为true。
3、两个查询函数 1)根据比赛索引查询竞猜信息 getGameInfo(uint8 gameIndex) 2)根据用户地址获取投注信息 getBetInfoByAddress(uint8 gameIndex, address sender)
接下来根据活动页的获奖记录top20中第一名的地址(0xb0c54aefe3a37d83138a59f000c662db98d20137)及其参与的比赛(俄罗斯VS克罗地亚),我们来查询一下他的投注记录。
根据迅雷链开放平台的文档,尝试使用迅雷链的接口直接查询合约,然后与后面的活动页接口查的数据作对比。 a. 根据abiCode编码函数和参数,查询比赛信息 首先,需要对 两个查询函数的调用做编码。拿到getGameInfo的abiCode,参数从0开始试。
b. 然后拿上面得到的data请求迅雷链的合约查询接口,to地址是合约地址,from地址不影响,随便用了一个文档里的。
4、解码 接下来把上面的结果解码
按照上述方法,最终尝试到`gameIndex = 12`时,查到这场竞猜是 俄罗斯VS克罗地亚。
查中奖组多的用户投注信息,参数(地址:0xb0c54aefe3a37d83138a59f000c662db98d20137),比赛ID:12 操作步骤跟上面相同:
根据返回值结构可以得知,用户地址为(0xb0c54aefe3a37d83138a59f000c662db98d20137)的投了151注平。根据步骤1里查的俄罗斯VS克罗地亚的结果8和9,可以得知此用户中奖比例
(151/658)2608=598.4924012158054,每注2链克,所以最终得链克为 (151/658)2608*2=1196.984802431611。官方结果取前8位,跟官方公布结果一致。
上面只是查询了此用户在俄罗斯VS克罗地亚的比赛里的投注,下面查询并统计了此用户在所有比赛里的投注信息。
用户地址 0xb0c54aefe3a37d83138a59f000c662db98d20137 的投注情况
查到上面数据后,只想说有链克真的可以为所欲为。。。
下面是统计到的每场竞猜的总投注数及结果,各位可以根据这个结果算一下得失。
三、从平台交易记录角度查数据 从迅雷链开放平台可以查到足球竞猜合约的所有交易记录,并且是实时的。从交易记录可以看出,交易一栏显示的转入地址都是合约的地址,内部交易一栏现实的转出地址都是合约地址。所有可以理解为交易栏就是用户投注调用合约的交易记录,内部交易栏就是发奖时从合约里转向外部用户地址的交易记录。可以根据区块高度会差别很大看出这是一个多链结构。value为2的就是投注的合约调用交易。
从交易记录可以查到每个地址的具体投注情况,以及竞猜结束后的发奖交易记录。如果对具体的账户交易感兴趣,可以把接口数据爬下来统计。
综上合约源码和交易记录分析可得,此足球竞猜活动通过智能合约的实现,的确是可信的去中心化应用。有兴趣的用户可以去查数据验证和统计。
|