目标

用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. [oeasy]python0073_进制转化_eval_evaluate_衡量_oct_octal_八进制

    进制转化 回忆上次内容 上次了解的是 整型数字类变量 integer 前缀为i   ​   添加图片注释,不超过 140 字(可选)   整型变量 和 字符串变量 不同 整型变量 是 直接存储二进制形 ...

  2. vue小知识~实现父子组件双向数据绑定

    vue的数据是单向数据流动,在子组件中是不可以修改父组件的数据的,但是还是可以通过其他方式间接修改父组件的数据. 核心思想:数据在哪个组件,就在哪个组件修改. 1,方式一:通过向子组件传递方法 这个方 ...

  3. docker 将镜像发布到网络

    1.发布自己的镜像 hub.docker.com 创建账号 docker login -u supermao -p xxxx docker tag ls supermaofox/ls:1.0 先打标签 ...

  4. layui表格列添加超链接并传参

    1.表格渲染中对列添加templet属性  addlink为方法名 tableIns = table.render({                elem: '#Test'            ...

  5. 全网最适合入门的面向对象编程教程:31 Python的内置数据类型-对象Object和类型Type

    全网最适合入门的面向对象编程教程:31 Python 的内置数据类型-对象 Object 和类型 Type 摘要: Python 中的对象和类型是一个非常重要的概念.在 Python 中,一切都是对象 ...

  6. 神州笔记本 —— HASEE神州 —— 用户手册(使用功能键)—— 笔记本电脑功能键

    功能键功能: FN+f1 启动/关闭 触摸板 FN+f2 启动/关闭 屏幕背光 FN+f3 启动/关闭 喇叭和外接耳机 FN+f5 减低音量 FN+f6 提高音量 FN+f7 切换屏幕 FN+f8 降 ...

  7. 如何在vscode中同时运行多个文件——server/client模式——在launch.json文件中设置多个configurations再compounds

    在vscode中我们一般都是同一时间只运行一个代码,但是这种设置并不适合server/client模式,甚至有很多分布式和并行的项目需要同一时间运行多个client,针对这种情况我们可以通过设置vsc ...

  8. 简单易懂的BFS

    最近学习BFS,看到许多教程都用C++内置的queue,但其实还有更简单的方法. 先了解概念:BFS与DFS不同,举个例子: 我们来用DFS遍历这棵树:A.B.D.E.G.C.F 但我们用BFS遍历这 ...

  9. SMU Summer 2024 Contest Round 4

    SMU Summer 2024 Contest Round 4 Made Up 题意 给你三个序列 \(A,B,C\) ,问你满足 \(A_i = B_{C_j}\) 的 \((i,j)\) 对有多少 ...

  10. springboot之banner.txt

    在springboot启动过程中,我们经常可以看到控制台打印下面图文: 实际上这个打印图文,是可以自定义的,可以在springboot的resource中创建一个banner.txt文件,在启动时就会 ...