目标

用vrf写一个随机红包

数据结构

红包:

struct Envelope {
Type t; // 类型,只是erc20 和eth红包
ERC20 token; // erc20 ,如果是erc20红包,这里是erc2o的地址
address sender; // 发红包的sender
uint balance; // 金额
bool allowAll; // 允许所有人领取
uint32 maxReceiver; // 最大领取数,eg:最多3个人领取红包
bool avg; // 平均主义,每个红包的价值等于balance/maxReceiver //填false则使用随机红包
uint avgMonty; // 平均金额
uint timeOutBlocks; //超时可以回收红包 ,也可以打开未领取完的红包
address[] received; // 已经领取过的列表
}

每个红包中储存红包的信息,可以在允许过程中发送红包

**存储数据: **

mapping(bytes32 => Envelope) public envelopes;   // 红包hash  -> 红包内容,领取红包时需要提供红包hash
mapping(bytes32 => mapping(address => bool)) public addressAllowList; // 红包对应的 allowlist 这个放在红包外面存是因为struct里面不能放map
mapping(bytes32 => mapping(address => bool)) addressGotList; // 已经领取的列表,与received有点重复,建议将received修改为一个int,记录有多少人领过
mapping(uint => bytes32) openWithVRF; // 红包对应的vrf, 当红包是随即红包时会用到这个
mapping(ERC20 => uint) ERC20Balance; // 每个erc20对应的金额,合约自己可以通过看自己的eth余额来判断,erc20需要单独记录,应为可以同时存在多个合约,如果多个合约都是同一个erc20,需要判断erc20的approve是否足够
mapping(bytes32 => uint[]) VRFKey; // vrf 对应的随机数列表 // VRFV2PlusClient public COORDINATOR;
bytes32 keyHash = 0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae; // VRF 用到的key,可以去官方文档查 uint256 s_subscriptionId; // vrf 用到的另一个key uint32 immutable callbackGasLimit = 100000; // 官方推荐配置 // The default is 3, but you can set this higher.
uint16 immutable requestConfirmations = 3; //官方推荐配置

上面的mapping 主要是红包合约的配置

下方的数据则是chainlink vrf的配置,这些key可以去官网查看具体的含义

合约的初始化

    constructor(
uint256 _subscriptionId,
address _coordinator
) VRFConsumerBaseV2Plus(_coordinator){
s_subscriptionId = _subscriptionId;
}

初始化主要是赋值vrf的订阅id(后续具体操作有详细过程)

构建红包

    function createETHredEnvelope(
bool allowAll,
address[] memory allowList,
uint32 maxReceiver,
bool avg,
uint timeOutBlocks
) public payable returns (bytes32) {}
  • allowAll:运行所有人领取,如果是true那么任何人都可以根据红包hash调用get方法领取红包
  • allowList:如果allowAll,那么allowList无用
  • maxReceiver:最大领取数,最大领取数可以比allowList小,这样代表有人领不到红包
  • avg: 是否平均,如果平均那么每个人领取到的金额 = msg.value/maxReceiver
  • timeOutBlocks:经过多少各block后超时,超时之后红包的发起人可以回收红包余额,或者打开红包
    function createERC20redEnvelope(
address token,
uint size, // erc20的数量
bool allowAll,
address[] memory allowList,
uint32 maxReceiver,
bool avg,
uint timeOutBlocks
) public returns (bytes32) {}

createERC20redEnvelopecreateETHredEnvelope 只是使用的是erc20

函数内的区别在与erc20要校验有没有足够的apporve

        uint approved = ERC20(token).allowance(msg.sender,address(this));
require(approved>=ERC20Balance[ERC20(token)]+size);
ERC20Balance[ERC20(token)] += size;

添加AllowList

    function allowSome(bytes32 hash, address[] memory allowList) public {
require(envelopes[hash].balance != 0, "envelop balance is 0");
require(envelopes[hash].sender == msg.sender,"only envelops sender can do this");
for (uint i = 0; i < allowList.length; i++) {
addressAllowList[hash][allowList[i]] = true;
}
}

这就不多解释了

领取红包

    function get(bytes32 hash) public {}

领红包的方法签名很简单,只需要传一个红包hash就可以,但内部逻辑很复杂,重点看一下它里面的判断

        require(envelopes[hash].balance != 0, "envelop balance is 0"); // 判读红包余额不为0
require(!addressGotList[hash][msg.sender], "has got"); // 判断发起人是否已经领取过
require( // 判断红包是否已经超时
envelopes[hash].timeOutBlocks > block.number,
"envelop timeOutBlocks is not enough"
);
require(
addressAllowList[hash][msg.sender] || envelopes[hash].allowAll,// 判断发起人是否被允许
"not allow"
);
require(envelopes[hash].received.length < envelopes[hash].maxReceiver, "no more"); // 还是判断是否已经领取完

在领取上有两种逻辑,一种是平均红包,平均红包get后会马上到账。一种是随机数红包,随机数红包不会立马到账需要等领红包的人数达到maxReceiver 或者红包超时,后面会详细讲怎么领随机数红包。

打开随机数红包

    function openEnvelopes(bytes32 hash)public{
require(
envelopes[hash].timeOutBlocks < block.number || envelopes[hash].received.length == envelopes[hash].maxReceiver,
"envelop timeOutBlocks is not enough"
);
require(envelopes[hash].maxReceiver > 0,"max receriver max more than 0");

打开随机数红包一般是在领取时自动调用,如果领取人没有达到maxReciver,可以在红包超时后手动调用。

这个方法中会向vrf请求一个随机数,正常情况chainlink会调用fulfillRandomWords方法来返回随机数。

    function fulfillRandomWords(
uint256 requestId,
uint256[] calldata randomWords
) internal override {
require(randomWords.length == envelopes[openWithVRF[requestId]].received.length);
VRFKey[openWithVRF[requestId]] = randomWords;
}

实际上可以在这个方法里面写红包分发的内容,但是由于这一步是chainlink触发的是由他来执行手续费,所以这里面逻辑不能太复杂(实际上限制的参数就是keyHash 这个变量)

手动打开红包

由于chainlink返回的时候不能有复杂的逻辑,所以随机数红包只能由手动触发

    function openVRFEnvelop(bytes32 hash)public {
uint[] memory randomWords = VRFKey[hash];
require(envelopes[hash].maxReceiver > 0,"max receriver max more than 0");
require(randomWords.length!=0,"can not get vrf words");
uint16[] memory words = new uint16[](randomWords.length);
// 计算每一个小分段的权重
}

vrf订阅id获取

首先我们需要去chainlink上领取一点测试币(link币和eth币,两个都要,如有已经有了可以跳过)

网址: https://faucets.chain.link/

然后需要去crf管理页面构建一个钱包合约,后面请求vrf随机数时会扣除Link币

网址:https://vrf.chain.link/

填完信息后,还是这样网址,下面会出现你的sub

点击你的sub,里面有sub的id,这个id就是合约部署时要用到的id,可以用这个id先把合约部署上去,后面要合约的地址

在这个页面的右下角找到fund 给这个sub冲点link币

冲完之后点左边的add cousumer ,把你的合约地址填进来

至此,这个红包合约就可以用了

测试

这个红包我已经部署在测试网络上了,可以直接去上面试试

https://sepolia.etherscan.io/address/0xc81c0913e6365eb31e761d1062b41dd5a96d2e90#code

合约源码后续会贴在这里(今天网太卡了,我环境一直下载不下来)

源码地址:(这两天环境弄好了我会把代码放上去,目前还是一个空项目)

https://github.com/bighu630/redEnvelop

chainLink vrf实验的更多相关文章

  1. CCIE路由实验(7) -- MPLS VPN

    1.LDP协议的各种情况2.LDP和BGP交互3.LDP高级部分4.MPLS VPN (RIP和静态)5.MPLS VPN (EIGRP)6.MPLS VPN (OSPF)7.MPLS VPN (EB ...

  2. 实验 MPLS LDP配置

    实验 MPLS LDP配置 一.学习目的 掌握启用和关闭MPLS的方法 掌握启用和关闭MPLS LDP配置方法 掌握使用MPLS LDP配置LSP的方法 二.拓扑图 三.场景 你是公司的网管员,公司的 ...

  3. CCNP路由实验之十二 MPLS

     个.第3个数据包„„同样的操作.包含查询路由表.重写MAC地址,CRC校验等. 系列路由器.或者12000系列路由器. Netflow switching 通过一种标准的交换机制,处理了流的第一 ...

  4. 实验3: DHCP 基本配置

    实验3-1: DHCP 基本配置 实验目的通过本实验可以掌握:(1)DHCP 的工作原理和工作过程(2)DHCP 服务器的基本配置和调试(3)客户端配置 拓扑结构 实验步骤n    步骤1:配置路由器 ...

  5. Nexus-配置vPC 实验二

    实验一中介绍的是单面的vPC,本实验配置的是dual site(双面vPC),这样的情况将上下的Port-channel都配置在了同一vPC下面. 实验拓扑如下: N5K-1配置:N5K-1(conf ...

  6. Nexus-vPC基础实验

    一.实验拓扑: 由于条件有限,使用两个N5K做基本的vPC实验,Peer Keepalive Link使用的是两个Nexus 5K的Mgm0接口. 二.配置步骤:1.先构建vPC domain,并在d ...

  7. IPSecVPN介绍 & (Cisco Packet Tracer)IPSecVPN实验演示

    一.基础知识 VPN(Virtual Private Network)虚拟专有网络,即虚拟专网.VPN可以实现在不安全的网络上,安全的传输数据,好像专网!VPN只是一个技术,使用PKI技术,来保证数据 ...

  8. VXLAN学习之路-结合VRF在Linux中实践VXLAN网络

    一.概述 近期在在搞网络安全HCIE.CISP的认证的事,顺便将VXLAN技术再次系统的学习一下,学习过程中看到云原生实验室里的一篇文章,就是关于VXLAN在Linux系统中的实践,感觉文章写得很好, ...

  9. [原] 利用 OVS 建立 VxLAN 虚拟网络实验

    OVS 配置 VxLAN HOST A ------------------------------------------ | zh-veth0(10.1.1.1) VM A | | ---|--- ...

  10. Android中Activity的四大启动模式实验简述

    作为Android四大组件之一,Activity可以说是最基本也是最常见的组件,它提供了一个显示界面,从而实现与用户的交互,作为初学者,必须熟练掌握.今天我们就来通过实验演示,来帮助大家理解Activ ...

随机推荐

  1. eclipse注释取消注释

    方法一:使用Ctrl+/快捷键   1 第1步:在Eclipse中拖动鼠标,选中需要注释的代码,通常为连续多行代码. 2 第2步:按住Ctrl+/快捷键,如图所示. 3 第3步:会发现所选代码被&qu ...

  2. 前端开发-- Webpack 代码分割和懒加载技术

    在现代前端开发中,优化应用性能是一个至关重要的任务.Webpack 作为一个强大的打包工具,为我们提供了代码分割和懒加载的功能,可以显著提升应用的加载速度和用户体验.本文将深入解析 Webpack 的 ...

  3. 扬州万方:基于申威平台的 Curve 块存储在高性能和超融合场景下的实践

    背景 扬州万方科技股份有限公司主要从事通信.计算机和服务器.智能车辆.基础软件等产品的科研生产,是国家高新技术企业.专精特新小巨人企业.国家火炬计划承担单位. 业务介绍 申威处理器是在国家" ...

  4. PyCharm配置Miniconda3

    打开PyCharm,点击"File"(文件)菜单,选择"Settings"(设置) 选择python interpreter中的配置 选择add 选择Conda ...

  5. 【RabbitMQ】09 深入部分P2 消费限流 & TTL

    1.消费限流设置 就是设置项的2个调整,当然还有前面的手动确认的监听改动处理 https://www.bilibili.com/video/BV15k4y1k7Ep?p=26 2.消息过时设置 TTL ...

  6. 【Java】JNDI实现

    前提情要: 培训的时候都没讲过,也是书上看到过这么个东西,进公司干外包的第二个项目就用了这个鬼东西 自学也不是没尝试过实现,结果各种失败,还找不到问题所在,索性不写了 JNDI实现参考: 目前参考这篇 ...

  7. 【Vue】Re20 VueX 第一部分(共享数据,Getters)

    一.概述 专门为VueJS应用程序开发的状态管理模式 集中式存储管理应用的所有组件的状态,按照相应的规则保证状态以一种可预测的方式发生变化 VueX也集成到了官方调试工具devtools extens ...

  8. 【Vue】Re09 Webpack 第一部分(介绍、安装、配置)

    一.Webpack的用途 webpack要解决的是统一网页资源的问题 前端工程化出现了很多问题,就是兼容性,浏览器所不能解析 所以需要一个打包,转换等方式处理 二.安装描述介绍 下载安装NodeJS, ...

  9. 【IDEA】回退操作记录

    参考自: https://www.cnblogs.com/zeussbook/p/9207970.html 找不到代码错误,又有很多已经写好的东西,不好全部删除 只要能记得确切的操作时间就行了 可以翻 ...

  10. 什么是snapshot isolation

    数据库常见的4种事务隔离级别: (源自:(34条消息) 8. 事务隔离级别: 总结_oyw5201314ck的博客-CSDN博客_ck事务隔离) 大多数的数据库默认的事务隔离级别是Repeatable ...