抢红包合约

1.实现功能
编写一个抢红包的智能合约,该合约应该包含以下功能:

  1. 发红包人可以设置红包的口令,类型,最多抢红包人数和红包有效时间。
  2. 可以查看某个人的某个红包当前剩余的钱。
  3. 可以查看当前所有红包剩余的钱。
  4. 可以查看当前红包中还有钱的对应的所有发钱包人的地址。
  5. 可以查看某个红包的抢红包结果。
  6. 可以查看某个人(地址)在某个发红包人发的某个红包中抢到了多少钱。
  7. 一个人可以发送多个红包,每个人对同一个红包只能够抢一次。
  8. 好友功能,只有红包拥有者的好友能够抢红包。
  9. 红包需要设置有效期,有效期内好友能够抢红包,有效期过后红包的拥有者能够撤回红包(仅仅在红包的超过有效期后,红包拥有者能够撤回红包)。
  10. 红包合约同时支持存在多个红包,并且任意的人能够调用红包合约不断新添加红包,每个红包对应自己的口令,抢红包的人需要输入该口令才能抢红包。
  11. 支持平分和随机分红包。

2.代码及注释

  • 本合约的运行版本及语言

  • 代码
pragma solidity ^0.4.0;contract red_envelope{address private owner;      //保存合约主人的地址uint uid = 0;       //记录当前发红包人的编号address[] user_ad; //记录当前发红包人的地址mapping(address => mapping(address => uint)) Friends;  //检查某个人是否是发红包人的好友的映射mapping(uint => address) I2U;       //发红包人编号到地址的映射mapping(address => Red_List) U2RE;    //发红包人地址到发送的红包的映射//红包的结构体struct Red_Envelope{mapping(address => uint) rewards;       //rewards用于保存每个人(地址)领取了多少红包uint left_money;      //left_money用于保存红包现在还剩下多少钱uint passwd;  //红包口令uint _type;       //红包类型uint max_receiver;        //红包最多可以有多少人收取uint average_money;       //若使用平均抢钱,红包平均钱的多少uint num;      // num用于保存当前已经有多少人领过红包了uint[] result;   //抢红包人的抢红包结果address[] ad_;  //抢到红包人的地址  uint end_time;  //红包的持续时间}//红包列表的结构体(一个人可以发送多个红包)struct Red_List{Red_Envelope[] red;      //用于存储多个红包uint[] lm;        //用于存储每个红包当前还剩下多少钱uint reid;        //用于存储红包的id(个数-1)}constructor() public payable {owner = msg.sender;      //设置第一个调用合约的人是合约的拥有者}//创建红包function create_RedEnvelope(uint password, uint __type, uint max_re, uint time_length) public payable {I2U[uid] = msg.sender;user_ad.push(msg.sender);uid++;address(this).send(msg.value);        //将钱发送到该合约中require( //抢红包人数不能为0max_re != 0,"You can't set the receiver number as 0");//对红包进行初始化并放入红包列表中U2RE[msg.sender].red.push(Red_Envelope({left_money: msg.value,passwd: password,_type: __type,max_receiver: max_re,average_money: msg.value / max_re,num: 0,result: new uint[](0),ad_: new address[](0),end_time: now + time_length}));//U2RE[msg.sender].reid++;U2RE[msg.sender].lm.push(msg.value);}//抢随机红包function get_random_money(uint uid, uint reid, uint password) public payable returns(uint){//根据发红包人id uid和红包id reid找到想要抢的红包address user = I2U[uid];      Red_Envelope storage re = U2RE[user].red[reid];require(        //检查口令re.passwd == password,"Wrong Password!"    );require(     //检查红包类型re._type == 0,"This red envelope is randomly distributed!" );require(       //检查当前抢红包的人是否以及抢了红包了re.rewards[msg.sender] == 0,"You have received your red envelope!");require(        //检查红包是否在有效期now < re.end_time,"This red envelope is expired!");require(        //检查抢红包的人是否是发红包人的好友Friends[user][msg.sender] == 1,"You haven't added the sender's friend!");require(      //检查红包是否还有钱re.left_money > 0,"The red envelope is empty!");    if (re.num == re.max_receiver - 1){       //对随机抢红包的最后一个人特殊处理:将剩余所有钱都给最后一个人re.rewards[msg.sender] = re.left_money;     //将最后一个人和抢到的红包存储起来re.result.push(re.left_money);        //将剩下的钱保存到抢钱记录数组中re.ad_.push(msg.sender);           //将最后一个人的地址保存到抢钱地址数组中msg.sender.send(re.left_money);        //发送钱给最后一个人U2RE[I2U[uid]].lm[reid] -= re.left_money;       //将当前红包的剩余钱清0re.left_money = 0;if (re.left_money == 0){  //在红包被抢完后,将发送人的地址从保存发送红包人地址数组中删除uint index;for (uint i = 0; i < user_ad.length; i++){if (I2U[uid] == user_ad[i]){index = i;break;}}for (uint j = index; j < user_ad.length - 1; j++){user_ad[j] = user_ad[j+1];}delete user_ad[user_ad.length - 1];user_ad.length -= 1;}return re.left_money;}//根据当前块的时间戳,区块的难度,以及是第几个抢的红包生成一个0~99随机数uint random = uint8(uint256(keccak256(block.timestamp, block.difficulty, re.num))%100);uint temp = random * re.left_money / 100;      //生成随机比例的红包re.left_money -= temp;      //将红包发给抢红包的人msg.sender.send(temp);U2RE[I2U[uid]].lm[reid] -= temp;     //跟新将当前红包的剩余钱re.rewards[msg.sender] = temp;        //保存某个人和这个人抢的红包的钱re.result.push(temp);re.ad_.push(msg.sender);re.num++;return re.left_money;}//抢平分红包function get_average_money(uint uid, uint reid, uint password) public payable {address user = I2U[uid]; Red_Envelope storage re = U2RE[user].red[reid];require(re.passwd == password,"Wrong Password!"    );require(re._type == 1,"This red envelope is evenly distributed!" );require(re.rewards[msg.sender] == 0,"You have received your red envelope!");require(now < re.end_time,"This red envelope is expired!");require(Friends[user][msg.sender] == 1,"You haven't added the sender's friend!");require(      //若当前抢红包的人数还没有到限制的人数re.num < re.max_receiver,"This red envelope reached its limit on the maximum number of receivers");require(re.left_money > 0,"The red envelope is empty!");       //若红包还有钱re.left_money -= re.average_money;msg.sender.send(re.average_money);U2RE[I2U[uid]].lm[reid] -= re.average_money;re.rewards[msg.sender] = re.average_money;       //保存某个人和这个人抢的红包的钱re.result.push(re.average_money);re.ad_.push(msg.sender);re.num++;//若平分红包的时候遇到了无法平分的情况,将剩余钱都给最后一个人if (re.num == re.max_receiver && re.left_money != 0){re.rewards[msg.sender] += re.left_money;re.result[re.num-1] += re.left_money;msg.sender.send(re.left_money);U2RE[I2U[uid]].lm[reid] -= re.average_money;re.left_money = 0;}if (re.left_money == 0){uint index;for (uint i = 0; i < user_ad.length; i++){if (I2U[uid] == user_ad[i]){index = i;break;}}for (uint j = index; j < user_ad.length - 1; j++){user_ad[j] = user_ad[j+1];}delete user_ad[user_ad.length - 1];user_ad.length -= 1;}}//获取当前红包内还有钱的所有发红包人地址function get_sender() public view returns(address[]) {return user_ad;}//获取某个发红包人所有红包的余额function get_re(uint uid) public view returns(uint[]) {return U2RE[I2U[uid]].lm;}//获得某个人抢红包抢了多少钱function get_rewards(uint uid, uint reid, address _ad) public view returns(uint) {address user = I2U[uid]; Red_Envelope storage re = U2RE[user].red[reid];return re.rewards[_ad];}//获得某个发红包人的某个红包的余额function get_leftmoney(uint uid, uint reid) public view returns(uint) {address user = I2U[uid]; Red_Envelope storage re = U2RE[user].red[reid];return re.left_money;}//获得某个发红包人的某个红包的抢红包情况function get_result(uint uid, uint reid) public view returns(uint, address, uint[]) {address user = I2U[uid]; Red_Envelope storage re = U2RE[user].red[reid];uint max = 0;if(re.num == re.max_receiver){re.num -= 1;}for(uint i = 1; i <= re.num; i++){if (re.result[max] < re.result[i])max = i;}return (max, re.ad_[max], re.result);        //返回运气王的编号,运气王的地址以及所有抢红包的情况}//添加给定发红包人编号的好友function add_friend(uint id) public {address user = I2U[id];        Friends[user][msg.sender] = 1;}//若时间超过且红包还有钱,发红包人可以将钱取回function withdraw(uint uid, uint reid) public payable{address user = I2U[uid];Red_Envelope storage re = U2RE[user].red[reid];require(now > re.end_time,"You can't withdraw your money before the red envelope is due!");require(re.left_money > 0,"This red envelope is empty!");require(msg.sender == user,"You are not the owner of the red envelope!");msg.sender.send(re.left_money);re.left_money = 0;}
}

代码优化版本:

pragma solidity ^0.4.0;contract red_envelope{address private owner;      //保存红包发起方的地址uint uid = 0;address[] user_ad;mapping(address => mapping(address => uint)) Friends;mapping(uint => address) I2U;mapping(address => Red_List) U2RE;struct Red_Envelope{mapping(address => uint) rewards;       //rewards用于保存每个人(地址)领取了多少红包uint left_money;       //left_money用于保存红包现在还剩下多少钱uint passwd;uint _type;uint max_receiver;uint average_money;uint num;     // num用于保存当前已经有多少人领过红包了uint[] result;address[] ad_;  uint end_time;      }struct Red_List{Red_Envelope[] red;uint[] lm;uint reid;}constructor() public payable {owner = msg.sender;        //设置}function create_RedEnvelope(uint password, uint __type, uint max_re, uint time_length) public payable {bool flag = true;for (uint i = 0; i < user_ad.length; i++){if (user_ad[i] == msg.sender){flag = false;break;}}if (flag){user_ad.push(msg.sender);I2U[uid] = msg.sender;uid++;    }address(this).send(msg.value);require(msg.value > 0,"The red envelope's money should lager than 0!");require(max_re != 0,"You can't set the receiver number as 0");require(__type == 0 || __type == 1,"Please enter 0 or 1 to select the red envelope type, 0 for randomly, 1 for evenly!");U2RE[msg.sender].red.push(Red_Envelope({left_money: msg.value,passwd: password,_type: __type,max_receiver: max_re,average_money: msg.value / max_re,num: 0,result: new uint[](0),ad_: new address[](0),end_time: now + time_length}));U2RE[msg.sender].reid++;U2RE[msg.sender].lm.push(msg.value);}function get(uint uid, uint reid, uint password) public payable {address user = I2U[uid]; Red_Envelope storage re = U2RE[user].red[reid];require(re.passwd == password,"Wrong Password!"    );// require(//     re._type == 0,//     "This red envelope is randomly distributed!" // );require(re.rewards[msg.sender] == 0,"You have received your red envelope!");require(now < re.end_time,"This red envelope is expired!");require(Friends[user][msg.sender] == 1,"You haven't added the sender's friend!");require(re.left_money > 0,"The red envelope is empty!");      //若红包还有钱if (re._type == 0){get_random_money(uid, reid, password);}else if (re._type == 1){get_average_money(uid, reid, password);}}function get_random_money(uint uid, uint reid, uint password) public payable returns(uint){address user = I2U[uid]; Red_List storage rel = U2RE[user];Red_Envelope storage re = rel.red[reid];if (re.num == re.max_receiver - 1){       //最多5个人,若已经是第5个人了,将红包剩余的钱都给第5个人re.rewards[msg.sender] = re.left_money;re.result.push(re.left_money);re.ad_.push(msg.sender);msg.sender.send(re.left_money);rel.lm[reid] = 0;re.left_money = 0;isDelete(user, rel, re);return re.left_money;}//根据当前块的时间戳,区块的难度,以及是第几个抢的红包生成一个0~99随机数uint random = uint8(uint256(keccak256(block.timestamp, block.difficulty, re.num))%100);uint temp = random * re.left_money / 100;        //生成随机比例的红包re.left_money -= temp;      //将红包发给抢红包的人msg.sender.send(temp);rel.lm[reid] -= temp;re.rewards[msg.sender] = temp;     //保存某个人和这个人抢的红包的钱re.result.push(temp);re.ad_.push(msg.sender);re.num++;return re.left_money;}function get_average_money(uint uid, uint reid, uint password) payable {address user = I2U[uid]; Red_List storage rel = U2RE[user];Red_Envelope storage re = rel.red[reid];require(re.num < re.max_receiver,"This red envelope reached its limit on the maximum number of receivers");re.left_money -= re.average_money;msg.sender.send(re.average_money);U2RE[I2U[uid]].lm[reid] -= re.average_money;re.rewards[msg.sender] = re.average_money;      //保存某个人和这个人抢的红包的钱re.result.push(re.average_money);re.ad_.push(msg.sender);re.num++;if (re.num == re.max_receiver && re.left_money != 0){re.rewards[msg.sender] += re.left_money;re.result[re.num-1] += re.left_money;msg.sender.send(re.left_money);U2RE[I2U[uid]].lm[reid] = 0;re.left_money = 0;}isDelete(user, rel, re);}function isDelete(address user, Red_List rel, Red_Envelope re) internal {bool flag = true;if (re.left_money == 0){uint index;for (uint i = 0; i < user_ad.length; i++){if (user == user_ad[i]){index = i;break;}}for (uint j = 0; j < rel.lm.length; j++){if (rel.lm[j] != 0){flag = false;break;}}if (flag){for (uint k = index; k < user_ad.length - 1; k++){user_ad[k] = user_ad[k+1];}delete user_ad[user_ad.length - 1];user_ad.length -= 1;}}}function get_sender() public view returns(address[]) {return user_ad;}function get_re(uint uid) public view returns(uint[]) {return U2RE[I2U[uid]].lm;}//获得某个人抢红包抢了多少钱function get_rewards(uint uid, uint reid, address _ad) public view returns(uint) {address user = I2U[uid]; Red_Envelope storage re = U2RE[user].red[reid];return re.rewards[_ad];}function get_leftmoney(uint uid, uint reid) public view returns(uint) {address user = I2U[uid]; Red_Envelope storage re = U2RE[user].red[reid];return re.left_money;}function get_result(uint uid, uint reid) public view returns(uint, address, uint[]) {address user = I2U[uid]; Red_Envelope storage re = U2RE[user].red[reid];uint max = 0;if(re.num == re.max_receiver){re.num -= 1;}for(uint i = 1; i <= re.num; i++){if (re.result[max] < re.result[i])max = i;}return (max, re.ad_[max], re.result);}function add_friend(uint id) public {address user = I2U[id]; Friends[user][msg.sender] = 1;}function withdraw(uint uid, uint reid) public payable{address user = I2U[uid];Red_Envelope storage re = U2RE[user].red[reid];require(now > re.end_time,"You can't withdraw your money before the red envelope is due!");require(re.left_money > 0,"This red envelope is empty!");require(msg.sender == user,"You are not the owner of the red envelope!");msg.sender.send(re.left_money);re.left_money = 0;U2RE[user].lm[reid] = 0;isDelete(user, U2RE[user], re)}
}

3.使用合约

  • 抢随机红包,设置红包大小为3000000wei,口令为123,最多可以有4个人抢红包,并且存活时间为300秒。
    创建红包。

  • 可以查询到该红包余额已经有3000000wei了

  • 若不是好友无法抢红包。



  • 以下用户添加发红包人的好友。


  • 开始抢随机红包。

  • 可以查看当前所有红包内还有余额的发送红包人地址。


  • 第5个人无法抢红包了。

  • 查看该红包的抢红包结果,分别是运气王的编号,地址和抢红包的结果

  1. 抢平均红包,设置红包大小为1000000wei,口令为1234,最多可以有3个人抢红包,并且存活时间为300秒。

  • 此下三个人抢红包

  • 查看红包发送者的地址和红包余额


  • 第一个人抢红包

  • 检查抢完后红包余额

  • 抢完后查看抢红包结果

  • 红包抢完后自动删除发红包人的地址,此下是其他人的地址

  1. 抢平均红包,设置红包大小为3000000wei,口令为123,最多可以有3个人抢红包,并且存活时间为1秒。


  • 创建好红包一秒后就已经无法抢红包了。

  • 如下账户添加好友后选择取钱



  • 发生过期异常

  • 但该红包中还是有余额的

  • 发红包人可以通过withdraw将红包中的钱拿回。

  • 钱已经收回了,但是运行撤回操作需要花费一定量的gas。

  1. 一个人可以发多个红包

  • 上述用户发送了如下两个红包

  • 可以看到上述发红包人地址是第四个,因此其地址编号为3,并且存在其他发红包人的地址

  • 查找编号为3的人发送的所有红包的余额如下

solidity抢红包合约的实现相关推荐

  1. Solidity智能合约库:区块链工程师的随身工具箱

    编者荐语: Solidity使用起来不如其他语言那般丝滑顺畅?安全事故难以避免?社区迎来适用于FISCO BCOS的Solidity智能合约库,轻松破解合约的各种小难题,让合约开发更加快速高效.省时省 ...

  2. 微众银行Solidity智能合约库:区块链工程师的随身工具箱

    区块链技术在经历了十余年的发展后,渐呈"燎原之势",不断在各行业落地生根.但同时,从技术的角度看,区块链应用开发仍然有着较高的门槛,存在不少痛点.为了提升应用开发各环节的用户体验, ...

  3. 以太坊solidity智能合约-生成随机数

    Solidity随机数生成 在以太坊的只能合约中,没有提供像其他面向对象编程一样的生成随机数的工具类或方法.其实,所谓的随机数也是伪随机的,没有哪一种语言能够真正的生成随机数. 对于solidity来 ...

  4. solidity投票合约在bcos上的部署及解析(三)

    solidity投票合约在bcos上的部署及解析(二) solidity投票合约在bcos上的部署及解析(一) 在上俩篇文章中我们分析了一个solidity语言编写的投票合约,现在我们要将写好的投票合 ...

  5. solidity智能合约implicit conversion异常

    问题场景 在使用^0.5.10版本的solidity时,如果使用this关键字会出现以下问题. 代码: require(tokenContract.balanceOf(this) >= _num ...

  6. Solidity 智能合约入门

    Solidity 智能合约入门 存储合约示例 将一个数据放置在链上 // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 &l ...

  7. solidity智能合约中tx.origin的正确使用场景

    简介 tx.origin是Solidity的一个全局变量,它遍历整个调用栈并返回最初发送调用(或事务)的帐户的地址.在智能合约中使用此变量进行身份验证会使合约容易受到类似网络钓鱼的攻击. 但针对tx. ...

  8. web3j用于solidity智能合约maven插件

    web3j maven插件用于基于solidity智能合约文件创建java类. 用法 插件的基本配置将从src/main/resources获取solidity文件,并将java类生成到src/mai ...

  9. 基于以太坊的次高价盲拍solidity智能合约(二)

    基于以太坊的次高价盲拍solidity智能合约(二) 4.揭标 5.第三方仲裁人终结拍卖 4.揭标 揭标的过程应该是本智能合约中最复杂且具有灵魂的关键步骤. 当每个发起过竞标的用户,利用该标的隐式价格 ...

最新文章

  1. sklearn FutureWarning: numpy not_equal will not check..., The comparison did not return the same
  2. 孤荷凌寒自学python第八十一天学习爬取图片1
  3. web框架django初探
  4. 阿里大数据分析与应用(part3)--常用的大数据分析平台
  5. Angular应用一个创建场景的问题分析
  6. Windows 2000安装和配置RIS服务
  7. 报错,o.h.engine.jdbc.spi.SqlExceptionHelper : Data truncation: Data too long for column ‘verify_msg‘
  8. 浅谈编程-----非计算机专业以及非培训班的一些感悟
  9. ElasticSearch学习(二):ElasticSearch下载与运行
  10. eclipse汉化方法
  11. GBDT算法详解算法实例(分类算法)
  12. ISSCC2019文章
  13. TAOCP-Reading-计算机程序设计艺术阅读-1-2
  14. 带自动还原魔方游戏源码
  15. 反向的css动画,动画方向 | animation-direction
  16. 用户运营中,怎么做好用户增长?
  17. 关于vSphere vMotion的讨论 -3
  18. mysql、oracle、sqlserver各自的默认端口号
  19. 旧金山大学网站的红黑树演示动画,益于理解红黑树
  20. 树上距离之和 1060E

热门文章

  1. C++ Primer 第五版 部分课后题答案
  2. 外贸进口业务管理解决方案丨汇信外贸软件
  3. JVAV笔记12——I/O流
  4. PHP判断一个点在矩形区域什么位置
  5. 双非计算机保研er的逆袭指南~
  6. js实现统计字符串长度包含中文英文特殊字符
  7. 达人评测 i3 13100f和i5 12400F选哪个好 酷睿i313100f和i512400F差距
  8. 游戏角色制作行业标准?点开看看吧,深度技术好文
  9. 实现导航栏渐变色,隐藏(类似知乎日报的主界面)
  10. oracle lmd0,oracle 10.2.0.1 rac的lmd进程的含义之一