From 0a2d712930705ac5e719ebe2aa8e55e0b0872311 Mon Sep 17 00:00:00 2001 From: yeecai Date: Sun, 30 Apr 2023 23:53:21 +0800 Subject: [PATCH] feat: udpate en/38-39 --- Languages/en/38_NFTSwap_en/NFTSwap.sol | 133 ++++++++++-------- Languages/en/38_NFTSwap_en/readme.md | 4 +- Languages/en/39_Random_en/Random.sol | 123 +++++++++------- .../en/39_Random_en/RandomNumberConsumer.sol | 53 +++---- Languages/en/39_Random_en/readme.md | 93 +++++++----- 5 files changed, 233 insertions(+), 173 deletions(-) diff --git a/Languages/en/38_NFTSwap_en/NFTSwap.sol b/Languages/en/38_NFTSwap_en/NFTSwap.sol index 972b18336..38b2fd994 100644 --- a/Languages/en/38_NFTSwap_en/NFTSwap.sol +++ b/Languages/en/38_NFTSwap_en/NFTSwap.sol @@ -5,98 +5,121 @@ import "../34_ERC721/IERC721.sol"; import "../34_ERC721/IERC721Receiver.sol"; import "../34_ERC721/WTFApe.sol"; -contract NFTSwap is IERC721Receiver{ - event List(address indexed seller, address indexed nftAddr, uint256 indexed tokenId, uint256 price); - event Purchase(address indexed buyer, address indexed nftAddr, uint256 indexed tokenId, uint256 price); - event Revoke(address indexed seller, address indexed nftAddr, uint256 indexed tokenId); - event Update(address indexed seller, address indexed nftAddr, uint256 indexed tokenId, uint256 newPrice); - - // 定义order结构体 - struct Order{ +contract NFTSwap is IERC721Receiver { + event List( + address indexed seller, + address indexed nftAddr, + uint256 indexed tokenId, + uint256 price + ); + event Purchase( + address indexed buyer, + address indexed nftAddr, + uint256 indexed tokenId, + uint256 price + ); + event Revoke( + address indexed seller, + address indexed nftAddr, + uint256 indexed tokenId + ); + event Update( + address indexed seller, + address indexed nftAddr, + uint256 indexed tokenId, + uint256 newPrice + ); + + // define the order structure + struct Order { address owner; - uint256 price; + uint256 price; } - // NFT Order映射 + // NFT Order mapping mapping(address => mapping(uint256 => Order)) public nftList; - fallback() external payable{} + fallback() external payable {} - // 挂单: 卖家上架NFT,合约地址为_nftAddr,tokenId为_tokenId,价格_price为以太坊(单位是wei) - function list(address _nftAddr, uint256 _tokenId, uint256 _price) public{ - IERC721 _nft = IERC721(_nftAddr); // 声明IERC721接口合约变量 - require(_nft.getApproved(_tokenId) == address(this), "Need Approval"); // 合约得到授权 - require(_price > 0); // 价格大于0 + // Pending order: The seller puts NFT on the shelf, the contract address is _nftAddr, the tokenId is _tokenId, and the price _price is Ethereum (the unit is wei) + function list(address _nftAddr, uint256 _tokenId, uint256 _price) public { + IERC721 _nft = IERC721(_nftAddr); // Declare IERC721 interface contract variables + require(_nft.getApproved(_tokenId) == address(this), "Need Approval"); // The contract is authorized + require(_price > 0); // price is greater than 0 - Order storage _order = nftList[_nftAddr][_tokenId]; //设置NF持有人和价格 + Order storage _order = nftList[_nftAddr][_tokenId]; //Set NF holder and price _order.owner = msg.sender; _order.price = _price; - // 将NFT转账到合约 + // Transfer NFT to contract _nft.safeTransferFrom(msg.sender, address(this), _tokenId); - // 释放List事件 + // Release the List event emit List(msg.sender, _nftAddr, _tokenId, _price); } - // 购买: 买家购买NFT,合约为_nftAddr,tokenId为_tokenId,调用函数时要附带ETH - function purchase(address _nftAddr, uint256 _tokenId) payable public { - Order storage _order = nftList[_nftAddr][_tokenId]; // 取得Order - require(_order.price > 0, "Invalid Price"); // NFT价格大于0 - require(msg.value >= _order.price, "Increase price"); // 购买价格大于标价 - // 声明IERC721接口合约变量 + // Purchase: The buyer purchases NFT, the contract is _nftAddr, the tokenId is _tokenId, and ETH is required when calling the function + function purchase(address _nftAddr, uint256 _tokenId) public payable { + Order storage _order = nftList[_nftAddr][_tokenId]; // get Order + require(_order.price > 0, "Invalid Price"); // NFT price is greater than 0 + require(msg.value >= _order.price, "Increase price"); // The purchase price is greater than the list price + // Declare IERC721 interface contract variables IERC721 _nft = IERC721(_nftAddr); - require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT在合约中 + require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT is in the contract - // 将NFT转给买家 + // Transfer NFT to buyer _nft.safeTransferFrom(address(this), msg.sender, _tokenId); - // 将ETH转给卖家,多余ETH给买家退款 + // Transfer ETH to the seller, and refund the excess ETH to the buyer payable(_order.owner).transfer(_order.price); - payable(msg.sender).transfer(msg.value-_order.price); + payable(msg.sender).transfer(msg.value - _order.price); - delete nftList[_nftAddr][_tokenId]; // 删除order + delete nftList[_nftAddr][_tokenId]; // delete order - // 释放Purchase事件 + // Release the Purchase event emit Purchase(msg.sender, _nftAddr, _tokenId, msg.value); } - // 撤单: 卖家取消挂单 + // Cancellation: The seller cancels the pending order function revoke(address _nftAddr, uint256 _tokenId) public { - Order storage _order = nftList[_nftAddr][_tokenId]; // 取得Order - require(_order.owner == msg.sender, "Not Owner"); // 必须由持有人发起 - // 声明IERC721接口合约变量 + Order storage _order = nftList[_nftAddr][_tokenId]; // get Order + require(_order.owner == msg.sender, "Not Owner"); // must be initiated by the owner + // Declare IERC721 interface contract variables IERC721 _nft = IERC721(_nftAddr); - require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT在合约中 - - // 将NFT转给卖家 + require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT is in the contract + + // Transfer NFT to seller _nft.safeTransferFrom(address(this), msg.sender, _tokenId); - delete nftList[_nftAddr][_tokenId]; // 删除order - - // 释放Revoke事件 + delete nftList[_nftAddr][_tokenId]; // delete order + + // Release the Revoke event emit Revoke(msg.sender, _nftAddr, _tokenId); } - // 调整价格: 卖家调整挂单价格 - function update(address _nftAddr, uint256 _tokenId, uint256 _newPrice) public { - require(_newPrice > 0, "Invalid Price"); // NFT价格大于0 - Order storage _order = nftList[_nftAddr][_tokenId]; // 取得Order - require(_order.owner == msg.sender, "Not Owner"); // 必须由持有人发起 - // 声明IERC721接口合约变量 + // Adjust price: The seller adjusts the pending order price + function update( + address _nftAddr, + uint256 _tokenId, + uint256 _newPrice + ) public { + require(_newPrice > 0, "Invalid Price"); // NFT price is greater than 0 + Order storage _order = nftList[_nftAddr][_tokenId]; // get Order + require(_order.owner == msg.sender, "Not Owner"); // must be initiated by the owner + // Declare IERC721 interface contract variables IERC721 _nft = IERC721(_nftAddr); - require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT在合约中 - - // 调整NFT价格 + require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT is in the contract + + // Adjust NFT price _order.price = _newPrice; - - // 释放Update事件 + + // Release the Update event emit Update(msg.sender, _nftAddr, _tokenId, _newPrice); } - - // 实现{IERC721Receiver}的onERC721Received,能够接收ERC721代币 + + // Implement onERC721Received of {IERC721Receiver}, able to receive ERC721 tokens function onERC721Received( address operator, address from, uint tokenId, bytes calldata data - ) external override returns (bytes4){ + ) external override returns (bytes4) { return IERC721Receiver.onERC721Received.selector; } } diff --git a/Languages/en/38_NFTSwap_en/readme.md b/Languages/en/38_NFTSwap_en/readme.md index 7730f4407..75befaaa7 100644 --- a/Languages/en/38_NFTSwap_en/readme.md +++ b/Languages/en/38_NFTSwap_en/readme.md @@ -44,12 +44,12 @@ The contract includes four events corresponding to the actions of listing (list) An `NFT` order is abstracted as the `Order` structure, which contains information about the listing price (`price`) and the owner (`owner`). The `nftList` mapping records the `NFT` series (contract address) and `tokenId` information that the order corresponds to. ```solidity - // 定义order结构体 + // Define the order structure struct Order{ address owner; uint256 price; } - // NFT Order映射 + // NFT Order mapping mapping(address => mapping(uint256 => Order)) public nftList; ``` diff --git a/Languages/en/39_Random_en/Random.sol b/Languages/en/39_Random_en/Random.sol index b2f5093ef..5c5fda271 100644 --- a/Languages/en/39_Random_en/Random.sol +++ b/Languages/en/39_Random_en/Random.sol @@ -2,98 +2,113 @@ pragma solidity ^0.8.4; /** -* 从github和npm导入 -* 导入文件存放于当前工作区的.deps目录下 -*/ + * import from github and npm + * Import files are stored in the .deps directory of the current workspace + */ 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参数 +contract RandomNumber is ERC721, VRFConsumerBase { + // NFT parameters + uint256 public totalSupply = 100; // total supply + uint256[100] public ids; // used to calculate tokenId that can be mint + uint256 public mintCount; // the number of mint, the default value is 0 + // chainlink VRF parameters bytes32 internal keyHash; uint256 internal fee; - // 记录VRF申请标识对应的mint地址 + // Record the mint address corresponding to the VRF application ID mapping(bytes32 => address) public requestToSender; + /** - * 使用chainlink VRF,构造函数需要继承 VRFConsumerBase - * 不同链参数填的不一样 - * 网络: Rinkeby测试网 - * Chainlink VRF Coordinator 地址: 0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B - * LINK 代币地址: 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 + * To use chainlink VRF, the constructor needs to inherit VRFConsumerBase + * The parameters of different chains are filled differently + * Network: Rinkeby test network + * Chainlink VRF Coordinator address: 0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B + * LINK token address: 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 * Key Hash: 0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311 */ - constructor() + constructor() VRFConsumerBase( 0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B, // VRF Coordinator - 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 // LINK Token + 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 // LINK Token ) ERC721("WTF Random", "WTF") { keyHash = 0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311; - fee = 0.1 * 10 ** 18; // 0.1 LINK (VRF使用费,Rinkeby测试网) + fee = 0.1 * 10 ** 18; // 0.1 LINK (VRF usage fee, Rinkeby test network) } - - /** - * 输入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 + /** + * Input a uint256 number and return a tokenId that can be mint + */ + function pickRandomUniqueId( + uint256 random + ) private returns (uint256 tokenId) { + // Calculate the subtraction first, then calculate ++, pay attention to the difference between (a++, ++a) + uint256 len = totalSupply - mintCount++; // mint quantity + require(len > 0, "mint close"); // all tokenIds are mint finished + uint256 randomIndex = random % len; // get the random number on the chain + + // Take the modulus of the random number to get the tokenId as an array subscript, and record the value as len-1 at the same time. If the value obtained by taking the modulus already exists, then tokenId takes the value of the array subscript + tokenId = ids[randomIndex] != 0 ? ids[randomIndex] : randomIndex; // get tokenId + ids[randomIndex] = ids[len - 1] == 0 ? len - 1 : ids[len - 1]; // update ids list + ids[len - 1] = 0; // delete the last element, can return gas } - /** - * 链上伪随机数生成 - * keccak256(abi.encodePacked()中填上一些链上的全局变量/自定义变量 - * 返回时转换成uint256类型 - */ - function getRandomOnchain() public view returns(uint256){ + /** + * On-chain pseudo-random number generation + * keccak256(abi.encodePacked() fill in some global variables/custom variables on the chain + * Convert to uint256 type when returning + */ + function getRandomOnchain() public view returns (uint256) { /* - * 本例链上随机只依赖区块哈希,调用者地址,和区块时间, - * 想提高随机性可以再增加一些属性比如nonce等,但是不能根本上解决安全问题 + * In this case, randomness on the chain only depends on block hash, caller address, and block time, + * If you want to improve the randomness, you can add some attributes such as nonce, etc., but it cannot fundamentally solve the security problem */ - bytes32 randomBytes = keccak256(abi.encodePacked(blockhash(block.number-1), msg.sender, block.timestamp)); + bytes32 randomBytes = keccak256( + abi.encodePacked( + blockhash(block.number - 1), + msg.sender, + block.timestamp + ) + ); return uint256(randomBytes); } - // 利用链上伪随机数铸造NFT + // Use the pseudo-random number on the chain to cast NFT function mintRandomOnchain() public { - uint256 _tokenId = pickRandomUniqueId(getRandomOnchain()); // 利用链上随机数生成tokenId + uint256 _tokenId = pickRandomUniqueId(getRandomOnchain()); // Use the random number on the chain to generate tokenId _mint(msg.sender, _tokenId); } - /** - * 调用VRF获取随机数,并mintNFT - * 要调用requestRandomness()函数获取,消耗随机数的逻辑写在VRF的回调函数fulfillRandomness()中 - * 调用前,把LINK代币转到本合约里 + /** + * Call VRF to get random number and mintNFT + * To call the requestRandomness() function to obtain, the logic of consuming random numbers is written in the VRF callback function fulfillRandomness() + * Before calling, transfer LINK tokens to this contract */ function mintRandomVRF() public returns (bytes32 requestId) { - // 检查合约中LINK余额 - require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet"); - // 调用requestRandomness获取随机数 + // Check the LINK balance in the contract + require( + LINK.balanceOf(address(this)) >= fee, + "Not enough LINK - fill contract with faucet" + ); + // Call requestRandomness to get a random number requestId = requestRandomness(keyHash, fee); requestToSender[requestId] = msg.sender; return requestId; } /** - * VRF的回调函数,由VRF Coordinator调用 - * 消耗随机数的逻辑写在本函数中 + * VRF callback function, called by VRF Coordinator + * The logic of consuming random numbers is written in this function */ - function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override { - address sender = requestToSender[requestId]; // 从requestToSender中获取minter用户地址 - uint256 _tokenId = pickRandomUniqueId(randomness); // 利用VRF返回的随机数生成tokenId + function fulfillRandomness( + bytes32 requestId, + uint256 randomness + ) internal override { + address sender = requestToSender[requestId]; // Get minter user address from requestToSender + uint256 _tokenId = pickRandomUniqueId(randomness); // Use the random number returned by VRF to generate tokenId _mint(sender, _tokenId); } } diff --git a/Languages/en/39_Random_en/RandomNumberConsumer.sol b/Languages/en/39_Random_en/RandomNumberConsumer.sol index bb48d57ce..b28311f26 100644 --- a/Languages/en/39_Random_en/RandomNumberConsumer.sol +++ b/Languages/en/39_Random_en/RandomNumberConsumer.sol @@ -4,48 +4,53 @@ pragma solidity ^0.8.4; import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol"; /** - * 申请测试网的 LINK 和 ETH 的水龙头: https://faucets.chain.link/ + * Faucets for LINK and ETH to apply for testnet: https://faucets.chain.link/ */ - + contract RandomNumberConsumer is VRFConsumerBase { - - bytes32 internal keyHash; // VRF唯一标识符 - uint256 internal fee; // VRF使用手续费 - - uint256 public randomResult; // 存储随机数 - + bytes32 internal keyHash; // VRF unique identifier + uint256 internal fee; // VRF usage fee + + uint256 public randomResult; // store random number + /** - * 使用chainlink VRF,构造函数需要继承 VRFConsumerBase - * 不同链参数填的不一样 - * 网络: Rinkeby测试网 - * Chainlink VRF Coordinator 地址: 0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B - * LINK 代币地址: 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 + * To use chainlink VRF, the constructor needs to inherit VRFConsumerBase + * The parameters of different chains are filled differently + * Network: Rinkeby test network + * Chainlink VRF Coordinator address: 0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B + * LINK token address: 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 * Key Hash: 0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311 */ - constructor() + constructor() VRFConsumerBase( 0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B, // VRF Coordinator - 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 // LINK Token + 0x01BE23585060835E02B77ef475b0Cc51aA1e0709 // LINK Token ) { keyHash = 0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311; - fee = 0.1 * 10 ** 18; // 0.1 LINK (VRF使用费,Rinkeby测试网) + fee = 0.1 * 10 ** 18; // 0.1 LINK (VRF usage fee, Rinkeby test network) } - - /** - * 向VRF合约申请随机数 + + /** + * Apply random number to VRF contract */ function getRandomNumber() public returns (bytes32 requestId) { - // 合约中需要有足够的LINK - require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet"); + // There needs to be enough LINK in the contract + require( + LINK.balanceOf(address(this)) >= fee, + "Not enough LINK - fill contract with faucet" + ); return requestRandomness(keyHash, fee); } /** - * VRF合约的回调函数,验证随机数有效之后会自动被调用 - * 消耗随机数的逻辑写在这里 + * The callback function of the VRF contract will be called automatically after verifying that the random number is valid + * The logic of consuming random numbers is written here */ - function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override { + function fulfillRandomness( + bytes32 requestId, + uint256 randomness + ) internal override { randomResult = randomness; } } diff --git a/Languages/en/39_Random_en/readme.md b/Languages/en/39_Random_en/readme.md index 87570cd4f..efe7049ad 100644 --- a/Languages/en/39_Random_en/readme.md +++ b/Languages/en/39_Random_en/readme.md @@ -205,62 +205,79 @@ In addition to the constructor function, the contract defines 5 other functions: - `fulfillRandomness()`: the callback function for `VRF`, which is automatically called by the `VRF` contract after verifying the authenticity of the random number. It uses the returned off-chain random number to mint an NFT. ```solidity - /** - * 输入uint256数字,返回一个可以mint的tokenId - * 算法过程可理解为:totalSupply个空杯子(0初始化的ids)排成一排,每个杯子旁边放一个球,编号为[0, totalSupply - 1]。 - 每次从场上随机拿走一个球(球可能在杯子旁边,这是初始状态;也可能是在杯子里,说明杯子旁边的球已经被拿走过,则此时新的球从末尾被放到了杯子里) - 再把末尾的一个球(依然是可能在杯子里也可能在杯子旁边)放进被拿走的球的杯子里,循环totalSupply次。相比传统的随机排列,省去了初始化ids[]的gas。 - */ - function pickRandomUniqueId(uint256 random) private returns (uint256 tokenId) { - 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 + /** + * Input a uint256 number and return a tokenId that can be mint + * The algorithm process can be understood as: totalSupply empty cups (0-initialized ids) are lined up in a row, and a ball is placed next to each cup, numbered [0, totalSupply - 1]. + Every time a ball is randomly taken from the field (the ball may be next to the cup, which is the initial state; it may also be in the cup, indicating that the ball next to the cup has been taken away, then a new ball is placed from the end at this time into the cup) + Then put the last ball (still may be in the cup or next to the cup) into the cup of the removed ball, and loop totalSupply times. Compared with the traditional random arrangement, the gas for initializing ids[] is omitted. + */ + function pickRandomUniqueId( + uint256 random + ) private returns (uint256 tokenId) { + // Calculate the subtraction first, then calculate ++, pay attention to the difference between (a++, ++a) + uint256 len = totalSupply - mintCount++; // mint quantity + require(len > 0, "mint close"); // all tokenIds are mint finished + uint256 randomIndex = random % len; // get the random number on the chain + + // Take the modulus of the random number to get the tokenId as an array subscript, and record the value as len-1 at the same time. If the value obtained by taking the modulus already exists, then tokenId takes the value of the array subscript + tokenId = ids[randomIndex] != 0 ? ids[randomIndex] : randomIndex; // get tokenId + ids[randomIndex] = ids[len - 1] == 0 ? len - 1 : ids[len - 1]; // update ids list + ids[len - 1] = 0; // delete the last element, can return gas } - /** - * 链上伪随机数生成 - * keccak256(abi.encodePacked()中填上一些链上的全局变量/自定义变量 - * 返回时转换成uint256类型 - */ - function getRandomOnchain() public view returns(uint256){ - // remix跑blockhash会报错 - bytes32 randomBytes = keccak256(abi.encodePacked(block.number, msg.sender, blockhash(block.timestamp-1))); + /** + * On-chain pseudo-random number generation + * keccak256(abi.encodePacked() fill in some global variables/custom variables on the chain + * Convert to uint256 type when returning + */ + function getRandomOnchain() public view returns (uint256) { + /* + * In this case, randomness on the chain only depends on block hash, caller address, and block time, + * If you want to improve the randomness, you can add some attributes such as nonce, etc., but it cannot fundamentally solve the security problem + */ + bytes32 randomBytes = keccak256( + abi.encodePacked( + blockhash(block.number - 1), + msg.sender, + block.timestamp + ) + ); return uint256(randomBytes); } - // 利用链上伪随机数铸造NFT + // Use the pseudo-random number on the chain to cast NFT function mintRandomOnchain() public { - uint256 _tokenId = pickRandomUniqueId(getRandomOnchain()); // 利用链上随机数生成tokenId + uint256 _tokenId = pickRandomUniqueId(getRandomOnchain()); // Use the random number on the chain to generate tokenId _mint(msg.sender, _tokenId); } - /** - * 调用VRF获取随机数,并mintNFT - * 要调用requestRandomness()函数获取,消耗随机数的逻辑写在VRF的回调函数fulfillRandomness()中 - * 调用前,把LINK代币转到本合约里 + /** + * Call VRF to get random number and mintNFT + * To call the requestRandomness() function to obtain, the logic of consuming random numbers is written in the VRF callback function fulfillRandomness() + * Before calling, transfer LINK tokens to this contract */ function mintRandomVRF() public returns (bytes32 requestId) { - // 检查合约中LINK余额 - require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet"); - // 调用requestRandomness获取随机数 + // Check the LINK balance in the contract + require( + LINK.balanceOf(address(this)) >= fee, + "Not enough LINK - fill contract with faucet" + ); + // Call requestRandomness to get a random number requestId = requestRandomness(keyHash, fee); requestToSender[requestId] = msg.sender; return requestId; } /** - * VRF的回调函数,由VRF Coordinator调用 - * 消耗随机数的逻辑写在本函数中 + * VRF callback function, called by VRF Coordinator + * The logic of consuming random numbers is written in this function */ - function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override { - address sender = requestToSender[requestId]; // 从requestToSender中获取minter用户地址 - uint256 _tokenId = pickRandomUniqueId(randomness); // 利用VRF返回的随机数生成tokenId - + function fulfillRandomness( + bytes32 requestId, + uint256 randomness + ) internal override { + address sender = requestToSender[requestId]; // Get minter user address from requestToSender + uint256 _tokenId = pickRandomUniqueId(randomness); // Use the random number returned by VRF to generate tokenId _mint(sender, _tokenId); } ```