Solidity

在solidity中迭代映射的最佳方法是什麼

  • February 16, 2022

我最近開始研究solidity。我想創建一個智能合約,使用者可以通過點擊UI 上的**“立即購買”按鈕來鑄造和擁有 LAND (NFT),並將 LAND 座標(x 和 y)發送到合約。我為此創建了一個單獨的智能合約。現在,如果某些使用者嘗試使用相同的座標購買/鑄造一個已經由其他地址鑄造/擁有的 NFT,我想恢復交易,那麼最好的方法是什麼?請檢查buyLand()**函式或瀏覽我的程式碼並建議我更好的做法。謝謝你!

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

interface ILandContract {
   function mint(address to, string memory tokenURI) external;
   function getTokenCount() external view returns(uint256);
}

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MintingContract is ReentrancyGuard, Ownable {

   IERC20 private Token;
   address private _landContractAddress;
   uint256 private _landPrice;
   uint256 public numberOfSold;

   struct ParcelsSold{
       uint x;
       uint y;
   }

   mapping (uint256 => ParcelsSold) coords;
   string[] private _landCoordinates;

   event LandSold(
       uint256 timestamp,
       address buyer,
       uint256 amount
   );

   constructor(address landContractAddress, IERC20 tokenAddress, uint256 initialLandPrice){
       _landContractAddress = landContractAddress;
       Token = tokenAddress;
       _landPrice = initialLandPrice;
       numberOfSold = 0;
   }

   function buyLand(string memory tokenURI, uint x, uint y) public nonReentrant {

       for(uint i=0; i< numberOfSold; i++){
           require(!(coords[i].x == x && coords[i].y == y), "Minting : Parcel Sold Already");
       }
       Token.transferFrom(msg.sender, owner(), _landPrice);
       ILandContract land = ILandContract(_landContractAddress);
       land.mint(msg.sender, tokenURI);
       numberOfSold++;

       uint256 tokenId = land.getTokenCount();

       ParcelsSold memory sold = ParcelsSold(x, y);
       coords[tokenId] = sold;

       emit LandSold(block.timestamp, msg.sender, _landPrice);
   }

}

for(uint i=0; i< numberOfSold是一個無限循環,是一個很大的禁忌。最終,1 筆交易的成本將超過區塊氣體限制,並且會恢復。此時buyLand會變磚。

嘗試:

//       x,                  y
mapping (uint256 => mapping (uint256 => ParcelInfo)) parcels;

您無法通過映射進行列舉。而且您不想再這樣做,因為那將是一個無限循環。但是,您可能希望跟踪出售的地塊,例如:

// Token ids perhaps?
uint256[] allSold;

但是永遠不要讓你的 Solidity 程式碼for對其進行操作。這增加了契約的複雜性。所以認真想想你的契約需要什麼,什麼可以外包給Web2.0伺服器。


改進:你做land.mint然後tokenId = land.getTokenCount()。這聽起來不對。現在你被乙太坊是“單執行緒”的事實所拯救。相反,mint應該返回 new tokenId,例如:

uint256 tokenId = land.mint(msg.sender, tokenURI);

引用自:https://ethereum.stackexchange.com/questions/121680