forked from AmazingAng/WTF-Solidity
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' of https://github.com/AmazingAng/WTF-Solidity
- Loading branch information
Showing
15 changed files
with
330 additions
and
264 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,109 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.4; | ||
|
||
/** | ||
* 从github和npm导入 | ||
* 导入文件存放于当前工作区的.deps目录下 | ||
*/ | ||
import "../34_ERC721/ERC721.sol"; | ||
import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol"; | ||
|
||
contract RandomNumber is ERC721, VRFConsumerBase{ | ||
// NFT参数 | ||
uint256 public totalSupply = 100; // 总供给 | ||
uint256[100] public ids; // 用于计算可以mint的tokenId | ||
uint256 public mintCount; // 已mint数量, 默认值为0 | ||
// chainlink VRF参数 | ||
bytes32 internal keyHash; | ||
uint256 internal fee; | ||
|
||
// 记录VRF申请标识对应的mint地址 | ||
mapping(bytes32 => address) public requestToSender; | ||
/** | ||
* 使用chainlink VRF,构造函数需要继承 VRFConsumerBase | ||
* 不同链参数填的不一样 | ||
* 网络: Rinkeby测试网 | ||
* Chainlink VRF Coordinator 地址: 0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B | ||
* LINK 代币地址: 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 | ||
* Key Hash: 0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311 | ||
*/ | ||
constructor() | ||
VRFConsumerBase( | ||
0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B, // VRF Coordinator | ||
0x01BE23585060835E02B77ef475b0Cc51aA1e0709 // LINK Token | ||
) | ||
ERC721("WTF Random", "WTF") | ||
{ | ||
keyHash = 0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311; | ||
fee = 0.1 * 10 ** 18; // 0.1 LINK (VRF使用费,Rinkeby测试网) | ||
} | ||
|
||
/** | ||
* 输入uint256数字,返回一个可以mint的tokenId | ||
*/ | ||
function pickRandomUniqueId(uint256 random) private returns (uint256 tokenId) { | ||
//先计算减法,再计算++, 关注(a++,++a)区别 | ||
uint256 len = totalSupply - mintCount++; // 可mint数量 | ||
require(len > 0, "mint close"); // 所有tokenId被mint完了 | ||
uint256 randomIndex = random % len; // 获取链上随机数 | ||
|
||
//随机数取模,得到tokenId,作为数组下标,同时记录value为len-1,如果取模得到的值已存在,则tokenId取该数组下标的value | ||
tokenId = ids[randomIndex] != 0 ? ids[randomIndex] : randomIndex; // 获取tokenId | ||
ids[randomIndex] = ids[len - 1] == 0 ? len - 1 : ids[len - 1]; // 更新ids 列表 | ||
ids[len - 1] = 0; // 删除最后一个元素,能返还gas | ||
} | ||
|
||
/** | ||
* 链上伪随机数生成 | ||
* keccak256(abi.encodePacked()中填上一些链上的全局变量/自定义变量 | ||
* 返回时转换成uint256类型 | ||
*/ | ||
function getRandomOnchain() public view returns(uint256){ | ||
/* | ||
* 本例链上随机只依赖区块哈希,调用者地址,和区块时间, | ||
* 想提高随机性可以再增加一些属性比如nonce等,但是不能根本上解决安全问题 | ||
*/ | ||
bytes32 randomBytes = keccak256(abi.encodePacked(blockhash(block.number-1), msg.sender, block.timestamp)); | ||
return uint256(randomBytes); | ||
} | ||
|
||
// 利用链上伪随机数铸造NFT | ||
function mintRandomOnchain() public { | ||
uint256 _tokenId = pickRandomUniqueId(getRandomOnchain()); // 利用链上随机数生成tokenId | ||
_mint(msg.sender, _tokenId); | ||
} | ||
|
||
/** | ||
* 调用VRF获取随机数,并mintNFT | ||
* 要调用requestRandomness()函数获取,消耗随机数的逻辑写在VRF的回调函数fulfillRandomness()中 | ||
* 调用前,把LINK代币转到本合约里 | ||
*/ | ||
function mintRandomVRF() public returns (bytes32 requestId) { | ||
// 检查合约中LINK余额 | ||
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet"); | ||
// 调用requestRandomness获取随机数 | ||
requestId = requestRandomness(keyHash, fee); | ||
requestToSender[requestId] = msg.sender; | ||
return requestId; | ||
} | ||
|
||
/** | ||
* VRF的回调函数,由VRF Coordinator调用 | ||
* 消耗随机数的逻辑写在本函数中 | ||
*/ | ||
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override { | ||
address sender = requestToSender[requestId]; // 从requestToSender中获取minter用户地址 | ||
uint256 _tokenId = pickRandomUniqueId(randomness); // 利用VRF返回的随机数生成tokenId | ||
_mint(sender, _tokenId); | ||
} | ||
} | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.4; | ||
|
||
import "https://github.com/AmazingAng/WTFSolidity/blob/main/34_ERC721/ERC721.sol"; | ||
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol"; | ||
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol"; | ||
|
||
contract Random is ERC721, VRFConsumerBaseV2{ | ||
// NFT相关 | ||
uint256 public totalSupply = 100; // 总供给 | ||
uint256[100] public ids; // 用于计算可供mint的tokenId | ||
uint256 public mintCount; // 已mint数量 | ||
|
||
// chainlink VRF参数 | ||
|
||
//VRFCoordinatorV2Interface | ||
VRFCoordinatorV2Interface COORDINATOR; | ||
|
||
/** | ||
* 使用chainlink VRF,构造函数需要继承 VRFConsumerBaseV2 | ||
* 不同链参数填的不一样 | ||
* 网络: Sepolia测试网 | ||
* Chainlink VRF Coordinator 地址: 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625 | ||
* LINK 代币地址: 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 | ||
* 30 gwei Key Hash: 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c | ||
* Minimum Confirmations 最小确认块数 : 3 (数字大安全性高,一般填12) | ||
* callbackGasLimit gas限制 : 最大 2,500,000 | ||
* Maximum Random Values 一次可以得到的随机数个数 : 最大 500 | ||
*/ | ||
address vrfCoordinator = 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625; | ||
bytes32 keyHash = 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c; | ||
uint16 requestConfirmations = 3; | ||
uint32 callbackGasLimit = 1_000_000; | ||
uint32 numWords = 1; | ||
uint64 subId; | ||
uint256 public requestId; | ||
|
||
// 记录VRF申请标识对应的mint地址 | ||
mapping(uint256 => address) public requestToSender; | ||
|
||
constructor(uint64 s_subId) | ||
VRFConsumerBaseV2(vrfCoordinator) | ||
ERC721("WTF Random", "WTF"){ | ||
COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); | ||
subId = s_subId; | ||
} | ||
|
||
/** | ||
* 输入uint256数字,返回一个可以mint的tokenId | ||
*/ | ||
function pickRandomUniqueId(uint256 random) private returns (uint256 tokenId) { | ||
//先计算减法,再计算++, 关注(a++,++a)区别 | ||
uint256 len = totalSupply - mintCount++; // 可mint数量 | ||
require(len > 0, "mint close"); // 所有tokenId被mint完了 | ||
uint256 randomIndex = random % len; // 获取链上随机数 | ||
|
||
//随机数取模,得到tokenId,作为数组下标,同时记录value为len-1,如果取模得到的值已存在,则tokenId取该数组下标的value | ||
tokenId = ids[randomIndex] != 0 ? ids[randomIndex] : randomIndex; // 获取tokenId | ||
ids[randomIndex] = ids[len - 1] == 0 ? len - 1 : ids[len - 1]; // 更新ids 列表 | ||
ids[len - 1] = 0; // 删除最后一个元素,能返还gas | ||
} | ||
|
||
/** | ||
* 链上伪随机数生成 | ||
* keccak256(abi.encodePacked()中填上一些链上的全局变量/自定义变量 | ||
* 返回时转换成uint256类型 | ||
*/ | ||
function getRandomOnchain() public view returns(uint256){ | ||
/* | ||
* 本例链上随机只依赖区块哈希,调用者地址,和区块时间, | ||
* 想提高随机性可以再增加一些属性比如nonce等,但是不能根本上解决安全问题 | ||
*/ | ||
bytes32 randomBytes = keccak256(abi.encodePacked(blockhash(block.number-1), msg.sender, block.timestamp)); | ||
return uint256(randomBytes); | ||
} | ||
|
||
// 利用链上伪随机数铸造NFT | ||
function mintRandomOnchain() public { | ||
uint256 _tokenId = pickRandomUniqueId(getRandomOnchain()); // 利用链上随机数生成tokenId | ||
_mint(msg.sender, _tokenId); | ||
} | ||
|
||
/** | ||
* 调用VRF获取随机数,并mintNFT | ||
* 要调用requestRandomness()函数获取,消耗随机数的逻辑写在VRF的回调函数fulfillRandomness()中 | ||
* 调用前,需要在Subscriptions中fund足够的Link | ||
*/ | ||
function mintRandomVRF() public { | ||
// 调用requestRandomness获取随机数 | ||
requestId = COORDINATOR.requestRandomWords( | ||
keyHash, | ||
subId, | ||
requestConfirmations, | ||
callbackGasLimit, | ||
numWords | ||
); | ||
requestToSender[requestId] = msg.sender; | ||
} | ||
|
||
/** | ||
* VRF的回调函数,由VRF Coordinator调用 | ||
* 消耗随机数的逻辑写在本函数中 | ||
*/ | ||
function fulfillRandomWords(uint256 requestId, uint256[] memory s_randomWords) internal override{ | ||
address sender = requestToSender[requestId]; // 从requestToSender中获取minter用户地址 | ||
uint256 tokenId = pickRandomUniqueId(s_randomWords[0]); // 利用VRF返回的随机数生成tokenId | ||
_mint(sender, tokenId); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,63 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.4; | ||
|
||
import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol"; | ||
|
||
/** | ||
* 申请测试网的 LINK 和 ETH 的水龙头: https://faucets.chain.link/ | ||
*/ | ||
|
||
contract RandomNumberConsumer is VRFConsumerBase { | ||
|
||
bytes32 internal keyHash; // VRF唯一标识符 | ||
uint256 internal fee; // VRF使用手续费 | ||
|
||
uint256 public randomResult; // 存储随机数 | ||
|
||
/** | ||
* 使用chainlink VRF,构造函数需要继承 VRFConsumerBase | ||
* 不同链参数填的不一样 | ||
* 网络: Rinkeby测试网 | ||
* Chainlink VRF Coordinator 地址: 0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B | ||
* LINK 代币地址: 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 | ||
* Key Hash: 0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311 | ||
*/ | ||
constructor() | ||
VRFConsumerBase( | ||
0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B, // VRF Coordinator | ||
0x01BE23585060835E02B77ef475b0Cc51aA1e0709 // LINK Token | ||
) | ||
{ | ||
keyHash = 0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311; | ||
fee = 0.1 * 10 ** 18; // 0.1 LINK (VRF使用费,Rinkeby测试网) | ||
} | ||
|
||
/** | ||
* 向VRF合约申请随机数 | ||
*/ | ||
function getRandomNumber() public returns (bytes32 requestId) { | ||
// 合约中需要有足够的LINK | ||
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet"); | ||
return requestRandomness(keyHash, fee); | ||
} | ||
|
||
/** | ||
* VRF合约的回调函数,验证随机数有效之后会自动被调用 | ||
* 消耗随机数的逻辑写在这里 | ||
*/ | ||
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override { | ||
randomResult = randomness; | ||
} | ||
} | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.4; | ||
|
||
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol"; | ||
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol"; | ||
|
||
contract RandomNumberConsumer is VRFConsumerBaseV2{ | ||
|
||
//请求随机数需要调用VRFCoordinatorV2Interface接口 | ||
VRFCoordinatorV2Interface COORDINATOR; | ||
|
||
// 申请后的subId | ||
uint64 subId; | ||
|
||
//存放得到的 requestId 和 随机数 | ||
uint256 public requestId; | ||
uint256[] public randomWords; | ||
|
||
/** | ||
* 使用chainlink VRF,构造函数需要继承 VRFConsumerBaseV2 | ||
* 不同链参数填的不一样 | ||
* 具体可以看:https://docs.chain.link/vrf/v2/subscription/supported-networks | ||
* 网络: Sepolia测试网 | ||
* Chainlink VRF Coordinator 地址: 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625 | ||
* LINK 代币地址: 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 | ||
* 30 gwei Key Hash: 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c | ||
* Minimum Confirmations 最小确认块数 : 3 (数字大安全性高,一般填12) | ||
* callbackGasLimit gas限制 : 最大 2,500,000 | ||
* Maximum Random Values 一次可以得到的随机数个数 : 最大 500 | ||
*/ | ||
address vrfCoordinator = 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625; | ||
bytes32 keyHash = 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c; | ||
uint16 requestConfirmations = 3; | ||
uint32 callbackGasLimit = 200_000; | ||
uint32 numWords = 3; | ||
|
||
constructor(uint64 s_subId) VRFConsumerBaseV2(vrfCoordinator){ | ||
COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); | ||
subId = s_subId; | ||
} | ||
|
||
/** | ||
* 向VRF合约申请随机数 | ||
*/ | ||
function requestRandomWords() external { | ||
requestId = COORDINATOR.requestRandomWords( | ||
keyHash, | ||
subId, | ||
requestConfirmations, | ||
callbackGasLimit, | ||
numWords | ||
); | ||
} | ||
|
||
/** | ||
* VRF合约的回调函数,验证随机数有效之后会自动被调用 | ||
* 消耗随机数的逻辑写在这里 | ||
*/ | ||
function fulfillRandomWords(uint256 requestId, uint256[] memory s_randomWords) internal override { | ||
randomWords = s_randomWords; | ||
} | ||
|
||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.