目标

用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. Cush:从辞职自学编程到被 Apple、PriceTag推荐

    名字:Cush 开发者 / 团队:ShaSha 平台:iOS.macOS 请简要介绍下这款产品 也许你听过记账可以帮助省钱,但总是浅尝辄止? 快试试 Cush!它精简了记账中所有复杂繁琐的步骤,简单精 ...

  2. windows安装PHP的redis

    一定要先看vc版本和位 配置php的redis扩展 以php7.3 nts版为例,不同的php版本对应不通的redis扩展:下载扩展文件:https://windows.php.net/downloa ...

  3. [oeasy]python0095_乔布斯求职_雅达利_atari_breakout_打砖块_布什内尔_游戏机_Jobs

    编码进化 回忆上次内容 上次 我们回顾了 电子游戏的历史 从 电子游戏鼻祖 双人网球 到 视频游戏 PingPong 再到 街机游戏 Pong 雅达利 公司 来了 嬉皮士 捣乱? 布什内尔 会如何 应 ...

  4. [oeasy]python0033_任务管理_jobs_切换任务_进程树结构_fg

    ​ 查看进程 回忆上次内容 上次先进程查询 ps -elf 查看所有进程信息 ps -lf 查看本终端相关进程信息 杀死进程 kill -9 PID 给进程发送死亡信号 运行多个 python3 sh ...

  5. [oeasy]教您玩转linux0001 - 先跑起来 🥊

    Python 什么是 Python? Python 很好用 适合初学者 而且在各个领域都很强大   ​   添加图片注释,不超过 140 字(可选)   后来居上 下图可以点开   ​   添加图片注 ...

  6. js 做树形数组查询筛选功能

    对二级菜单进行搜索查询: watch: { librarySearch(val) { if(val == '') { this.libraryFiles = this.libraryFilesAll ...

  7. Scratch作品-巴黎2024奥运会

    ​ <Scratch作品-巴黎2024奥运会>是一款以巴黎2024年奥运会为主题的互动作品,专为儿童和青少年设计.通过Scratch编程语言,这个作品生动地再现了奥运会的精彩瞬间,结合了动 ...

  8. VSCode的安装

    VSCode(visual studio code),是一款功能强大且易用的编辑器.支持JavaScript.Node.js,也提供其他语言如(C ++,C#,Python,PHP,Go)的扩展插件. ...

  9. 【Git】GithubDesktop 忽略文件无法忽略BUG

    问题描述: 从仓库拉取的[.gitignore]忽略配置文件,在项目跑起来之后会生成诸多.idea文件,target打包文件 一开始没有忽略,但是发现使用GD配置之后忽略无效: 解决办法: 做一次随便 ...

  10. chatgpt的api联网报错问题解决:openai公司的api联网报错解决

    chatgpt是啥,这里不讲,openai是啥这里也不讲.要知道我们不论是通过网页web使用chatgpt还是使用api方式通过客户端使用chatgpt都是需要使用外国IP的, 为啥我们不能访问ope ...