chainLink vrf实验
目标
用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) {}
createERC20redEnvelope 与createETHredEnvelope 只是使用的是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币

填完信息后,还是这样网址,下面会出现你的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实验的更多相关文章
- 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 ...
- 实验 MPLS LDP配置
实验 MPLS LDP配置 一.学习目的 掌握启用和关闭MPLS的方法 掌握启用和关闭MPLS LDP配置方法 掌握使用MPLS LDP配置LSP的方法 二.拓扑图 三.场景 你是公司的网管员,公司的 ...
- CCNP路由实验之十二 MPLS
个.第3个数据包„„同样的操作.包含查询路由表.重写MAC地址,CRC校验等. 系列路由器.或者12000系列路由器. Netflow switching 通过一种标准的交换机制,处理了流的第一 ...
- 实验3: DHCP 基本配置
实验3-1: DHCP 基本配置 实验目的通过本实验可以掌握:(1)DHCP 的工作原理和工作过程(2)DHCP 服务器的基本配置和调试(3)客户端配置 拓扑结构 实验步骤n 步骤1:配置路由器 ...
- Nexus-配置vPC 实验二
实验一中介绍的是单面的vPC,本实验配置的是dual site(双面vPC),这样的情况将上下的Port-channel都配置在了同一vPC下面. 实验拓扑如下: N5K-1配置:N5K-1(conf ...
- Nexus-vPC基础实验
一.实验拓扑: 由于条件有限,使用两个N5K做基本的vPC实验,Peer Keepalive Link使用的是两个Nexus 5K的Mgm0接口. 二.配置步骤:1.先构建vPC domain,并在d ...
- IPSecVPN介绍 & (Cisco Packet Tracer)IPSecVPN实验演示
一.基础知识 VPN(Virtual Private Network)虚拟专有网络,即虚拟专网.VPN可以实现在不安全的网络上,安全的传输数据,好像专网!VPN只是一个技术,使用PKI技术,来保证数据 ...
- VXLAN学习之路-结合VRF在Linux中实践VXLAN网络
一.概述 近期在在搞网络安全HCIE.CISP的认证的事,顺便将VXLAN技术再次系统的学习一下,学习过程中看到云原生实验室里的一篇文章,就是关于VXLAN在Linux系统中的实践,感觉文章写得很好, ...
- [原] 利用 OVS 建立 VxLAN 虚拟网络实验
OVS 配置 VxLAN HOST A ------------------------------------------ | zh-veth0(10.1.1.1) VM A | | ---|--- ...
- Android中Activity的四大启动模式实验简述
作为Android四大组件之一,Activity可以说是最基本也是最常见的组件,它提供了一个显示界面,从而实现与用户的交互,作为初学者,必须熟练掌握.今天我们就来通过实验演示,来帮助大家理解Activ ...
随机推荐
- 【算法】用c#实现计算方法中的经典降幂优化策略,减少计算复杂度
对于给定的数组[x1,x2,x3,-,xn],计算幂的累积:x1^(x2^(x3^(-^xn))的最后一位(十进制)数字. 例如,对于数组[3,4,2],您的代码应该返回1,因为3^(4^2)=3^1 ...
- SpringBoot实战:轻松实现接口数据脱敏
引言 在现代的互联网应用中,数据安全和隐私保护变得越来越重要.尤其是在接口返回数据时,如何有效地对敏感数据进行脱敏处理,是每个开发者都需要关注的问题.本文将通过一个简单的Spring Boot项目,介 ...
- redis雪崩
每个key(即数据)如果设置了失效时间的话,如果大量key同时过期的时候,或者说因为某种原因redis中的数据突然大批量丢失,这些key又大量地去请求这些key时,因为redis里面没有这些数据,就会 ...
- [oeasy]python0010_怎么用命令行保存文件
编写 py 文件 回忆上次内容 上次 真的输出了 程序员的浪漫 Hello world! print函数 可以输出 字符串 但是 print这个词 别拼错 就连 大小写 也别能错 错了就改 也没事 ...
- [oeasy]python0007-调试程序_debug
调试程序 回忆上次内容 py 的程序是按照顺序执行的 是一行行挨排解释执行的 程序并不是数量越多越好 kpi也在不断演化 编辑 写的代码越多 出现的bug就越多 什么是bug 如何找bu ...
- 【JavaScript高级01】JavaScript基础深入
1,数据类型 JavaScript将数据分为六大类型,分别为数值类型(number).字符串类型(string).布尔类型(boolean).undefined(定义未赋值).null(赋值为空值). ...
- 周末玩一下云技术,kvm 相关笔记
由于需要将企业的很贵的显卡和主机装在一个虚拟主机,用来跑 ue5 和 sd3 用来给用户临时使用,但是怎么将主机虚拟出来成多个主机呢,自己没有有钱请不起人,只能自己学一下虚拟化技术,第一步主机开启 ...
- 全网最适合入门的面向对象编程教程:27 类和对象的Python实现-Python中异常层级与自定义异常类的实现
全网最适合入门的面向对象编程教程:27 类和对象的 Python 实现-Python 中异常层级与自定义异常类的实现 摘要: 本文主要介绍了在使用 Python 进行面向对象编程时,异常的层级和如何使 ...
- 从C++看C#托管内存与非托管内存
进程的内存 一个exe文件,在没有运行时,其磁盘存储空间格式为函数代码段+全局变量段.加载为内存后,其进程内存模式增加为函数代码段+全局变量段+函数调用栈+堆区.我们重点讨论堆区. 进程内存 函数代码 ...
- .NET8 Blazor 从入门到精通:(一)关键概念
目录 Blazor 的关键概念 项目模板 Razor 语法 依赖注入 注入配置 HeadOutlet 组件 @code 分离 Blazor 调试 CSS 隔离 调用JavaScript 最近在学习 B ...