Solidity
在solidity中迭代映射的最佳方法是什麼
我最近開始研究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
應該返回 newtokenId
,例如:uint256 tokenId = land.mint(msg.sender, tokenURI);