摘要:合约编写可以看出合约需要实现用户投注生成随机数发放奖励奖池余额查询的功能,接下来编写我们的合约代码。总结当前随机数的实现通过链上信息生成,这种生成随机数的方式容易受到不诚实的节点攻击。
导读:
本文旨在引导对 DApp 开发感兴趣的开发者,构建一个基于以太坊去中心化应用,通过开发一款功能完备的竞猜游戏,迈出 DApp 开发的第一步,通过实例讲解 Solidity 语言的常用语法,以及前端如何与智能合约进行交互。
如果正在阅读的你,从未接触过 DApp 开发也不要紧,可以先阅读【区块链上编程:DApp开发简介】进行前置知识补充。
随着加密猫、FOMO3D 等游戏的火爆,去中心化应用在游戏领域遍地开花,下面就带着大家一起开发一款简单有趣的 DApp 游戏,帮助大家熟悉 DApp 开发。
本 DApp 实现的合约功能:用户从 0-6 的数字中,任意组合三位数进行投注,合约计算出 3 位随机数,根据随机数的组合规则分别给予用户不同倍数的奖励,如随机数为 AAA ,A 等于 6 则奖励至少 20 倍投注金额,即奖池所有余额;A 不等于 6 则奖励 5 倍投注金额;随机数为 AAB,则奖励 2 倍投注金额;随机数为 ABC 则不奖励,同时用户可查看奖池余额和个人投注记录。
合约编写可以看出合约需要实现用户投注、生成随机数、发放奖励、奖池余额查询的功能,接下来编写我们的合约代码。
新建Lottery.sol合约文件,声明合约版本,^表示合约编译版本为 0.4.0 至 0.5.0(不含 0.5.0)。
pragma solidity ^0.4.0;
定义合约基本内容,同时声明最低投注金额。
contract Lottery { uint public betMoney = 10 finney; }
生成随机数,通过区块难度block.difficulty和内置函数keccak256生成随机数,在EVM中常用的数据存储位置:memory、storage,函数的参数、返回值默认存储在memory中,状态变量默认存储在storage中,我们可以通过声明memory、storage改变默认存储位置,两者的存储都需要消耗gas,但storage的开销远大于memory。
contract Lottery { ... function generateRandomNumber() private view returns(uint[]) { uint[] memory dices = new uint[](3); for (uint i = 0; i < 3; i++) { dices[i] = uint(keccak256(abi.encodePacked(block.difficulty, now, i))) % 6 + 1; } return dices; } ... }
获取合约余额,address类型比较重要的成员属性主要有balance、transfer,分别为获取地址余额、转移eth至该地址,默认eth单位是wei。
contract Lottery { ... function getBankBalance() public view returns(uint) { return address(this).balance; } ... }
用户投注,投注方法需要使用payable关键字描述,用来表示可以接收eth;通过msg.sender和msg.value获得交易发送者地址和当前交易附带的eth。通常使用require来校验外部输入参数,当判定条件为false时,则会将剩余的gas退回,同时回滚交易;assert则用来处理合约内部的逻辑错误,当错误发生时会消耗掉所有gas,同时回滚交易。
contract Lottery { ... function bet() public payable { uint amount = msg.value; require(amount >= betMoney, "bet money not less than 10 finney"); require(address(this).balance >= amount * 20, "contract money not enough to pay reward"); uint[] memory dices = generateRandomNumber(); require(dices.length == 3, "dices illegal"); address addr = msg.sender; bool isReward = false; uint reward = 0; if ((dices[0] == dices[1]) && (dices[1] == dices[2]) && (dices[0] == 6)) { isReward = true; reward = address(this).balance; } else if ((dices[0] == dices[1]) && (dices[1] == dices[2]) && (dices[0] != 6)) { isReward = true; reward = amount * 5; } else if ((dices[0] == dices[1]) || (dices[0] == dices[2]) || (dices[1] == dices[2])) { isReward = true; reward = amount * 2; } if (isReward) { addr.transfer(reward); } } ...
定义事件,通过合约内部触发事件,web3 监听到事件回调进行相应逻辑处理,从而进行页面 UI 更新;同时前端也可以通过对应事件名称获取日志信息。
contract Lottery { ... event BetList( address addr, uint amount, bool isReward, uint reward, uint[] dices ); function bet() public payable { ... emit BetList(addr, amount, isReward, reward, dices); } ...与合约进行交互
至此,我们已经写完了合约代码,前端页面实现就不在此赘述,主要介绍如何使用 web3 与合约交互,这里使用到的 web3 版本是 1.0,web3 1.0 和 0.2x.x 的 API 调用方式差别较大,1.0 的 API 支持异步调用。
安装 Metamask 浏览器插件后,会在浏览器页面内注入一个 web3 实例。检测页面中是否存在 web3 实例,如果不存在则连接自己的实例。
import Web3 from "web3"; if (typeof web3 !== "undefined") { web3 = new Web3(web3.currentProvider); } else { web3 = new Web3(new Web3.providers.HttpProvider(NODE_NRL)); }
传入合约 ABI,合约地址,实例化合约对象。
this.contract = new web3.eth.Contract( CONTRACT_ABI, CONTRACT_ADDR, );
调用合约中的投注方法,通过try catch可以捕获到 Metamask 弹窗取消交易操作。
userBet = async () => { try { await this.contract.methods .bet( ... ) .send({ from: ACCOUNT, value: MONEY, }); } catch (error) { ... } }
查询记录的日志,可以通过指定事件名称、区块高度及过滤条件来进行日志查询,值得注意的是,在合约内不能查询到日志信息。
queryEvent = async () => { const event = await this.contract.getPastEvents( EVENT_NAME, { filter: {}, fromBlock: 0, toBlock: "latest", } ) }功能拓展
比如修改用户投注金额及充值这类敏感操作,就需要管理员的权限来进行操作。同样地,我们也可以拓展赞助商的功能,通过充值奖池的累计金额排名来展示赞助商的广告,这里就不做展开了。
定义修饰器,在构造函数里设置管理员地址,将创建合约的账户设置为管理员。
contract Lottery { ... address public owner; modifier onlyOwner() { require(owner == msg.sender); _; } constructor() public { owner = msg.sender; } ... }
实现修改投注金额的功能,仅管理员账户可触发。
contract Lottery { ... function setBetMoney(uint _betMoney) public onlyOwner { betMoney = _betMoney; } function deposit() public payable onlyOwner {} ... }总结
当前随机数的实现通过链上信息生成,这种生成随机数的方式容易受到不诚实的节点攻击。下一篇文章将通过多个实例介绍相应的第三方工具库的使用(Oricalize、SafeMath、OpenZepplin),生成安全的随机数。
参考资料Solidity
Web3js
Cryptozombies
Coursetro
前置文章:
在区块链上编程:DApp 开发简介
文 / ielapp
一个简单的程序员编 / 荧声
本文已由作者授权发布,版权属于创宇前端。欢迎注明出处转载本文。本文链接:https://knownsec-fed.com/2018...
想要订阅更多来自知道创宇开发一线的分享,请搜索关注我们的微信公众号:创宇前端(KnownsecFED)。欢迎留言讨论,我们会尽可能回复。
欢迎点赞、收藏、留言评论、转发分享和打赏支持我们。打赏将被完全转交给文章作者。
感谢您的阅读。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/24326.html
摘要:目前通常指代基于以太坊或者上的智能合约开发的相关应用。引入以太坊通过的交互流程大致如下总结随着区块链近些年的大红大紫,被推上了风口浪尖,本文从技术的角度大致介绍了一下所涉及的技术要点。 当你开始探索区块链开发,需要了解到这些。 showImg(https://segmentfault.com/img/remote/1460000016608233?w=1370&h=389); 一、DA...
摘要:以太坊将成为新互联网的支柱,我为什么这么说正在以太坊上构建我们的第层,而不是其他区块链平台这就是原因。以太坊不会牺牲去中心化的原则而下沉权力在区块链方面,有一项称为可扩展性三难的基本法则。 以太坊将成为新互联网的支柱,我为什么这么说?Loom Network正在以太坊上构建我们的第2层,而不是其他区块链平台——这就是原因。 每个月都有其他的公司发布白皮书,声称已经解决了以太坊所面临的可...
摘要:将基于和开发的放在区块链系统上,结合智能合约,就成了。应用的数据加密后存储在公开的区块链上,所有对基础区块链技术的安全性稳定性及持续性要求较高。以太猫本身具有虚拟货币的功能,每只猫都是独特的交易于区块链的不可变更物体。启迪云-高级开发工程师 严刚前言2018年以来,区块链(blockchain)无疑是最火的科技之一,新闻媒体大量报道,宣称它将创造未来。我们该怎样参与?买几个币算不算呢?其实也...
摘要:下一代去中心化预言机服务网络台北圆满落幕年月日,由,携手共同联合举办的台北线下在台北的联合创业办公社圆满落幕。网络担任台北站活动嘉宾暨讲师活动开头,由网络介绍网络本身架构以及预言机在现实生活中的应用场景,范例。 showImg(https://segmentfault.com/img/bVbrNsK?w=1200&h=800);下一代去中心化预言机服务网络DOS Network台北Me...
摘要:我们目前正处于一个新兴的区块链开发行业中。,一种在以太坊开发人员中流行的新的简单编程语言,因为它是用于开发以太坊智能合约的语言。它是全球至少万开发人员使用的世界上最流行的编程语言之一。以太坊,主要是针对工程师使用进行区块链以太坊开发的详解。 我们目前正处于一个新兴的区块链开发行业中。区块链技术处于初期阶段,然而这种颠覆性技术已经成功地风靡全球,并且最近经历了一场与众不同的繁荣。由于许多...
阅读 1959·2021-10-13 09:39
阅读 3390·2021-09-30 09:52
阅读 778·2021-09-26 09:55
阅读 2757·2019-08-30 13:19
阅读 1866·2019-08-26 10:42
阅读 3169·2019-08-26 10:17
阅读 524·2019-08-23 14:52
阅读 3611·2019-08-23 14:39