Встречали проекты, где виртуальная земля продаётся как NFT, а потом никто не знает, что с ней делать? Без продуманной архитектуры координатной системы, гибкой системы прав и экономики с дефицитом карта остаётся пустой. Мы разработали десятки таких систем — от простых 2D гридов до полноценных 3D миров. Закажите разработку virtual land под ключ — от смарт-контрактов до клиентского рендеринга.
Основные проблемы: как хранить координаты в смарт-контрактах без безумных газ-трат? Как объединять участки в Estate с проверкой смежности? Как дать владельцам права настройки своей земли? Ниже разберём каждую из проблем с кодом и цифрами.
Координатная система и хранение
Земля обычно представлена как 2D Grid — целочисленные координаты (x, y). Каждый участок — уникальный NFT с координатами как ключевым атрибутом. Упаковка координат в tokenId (x: int16, y: int16 → uint32) ограничивает мир, но снижает газ.
contract VirtualLand is ERC721 { struct LandInfo { int16 x; int16 y; address owner; bool developed; uint32 districtId; } mapping(uint256 => LandInfo) public lands; mapping(bytes32 => uint256) public coordsToTokenId; function _coordsToId(int16 x, int16 y) internal pure returns (uint256) { return uint256(uint32(uint16(int16(x))) | (uint32(uint16(int16(y))) << 16)); } function _hashCoords(int16 x, int16 y) internal pure returns (bytes32) { return keccak256(abi.encodePacked(x, y)); } function mint(int16 x, int16 y, address to) external onlyMinter { bytes32 coordHash = _hashCoords(x, y); require(coordsToTokenId[coordHash] == 0, "Land already exists"); uint256 tokenId = _coordsToId(x, y); _safeMint(to, tokenId); lands[tokenId] = LandInfo({x: x, y: y, owner: to, developed: false, districtId: _getDistrictId(x, y)}); coordsToTokenId[coordHash] = tokenId; } } Estate: объединение участков
Estate — несколько соседних участков, объединённых в один NFT. Упрощает управление большим пространством. Проверка смежности on-chain — дорогая для крупных объединений, поэтому для estates до 20–30 участков используется O(n²) алгоритм, а для больших — off-chain с Merkle proof или ZK proof.
Детали проверки смежности
Для on-chain проверки можно использовать алгоритм поиска в глубину (DFS), ограниченный по газу. Примерный лимит — 2000 единиц на участок. Off-chain с Merkle proof дешевле в 10 раз.Как проверить смежность участков on‑chain?
Проверка того, что набор участков образует связный граф, — дорогая on-chain операция. Оптимизация: проверять, что каждый участок имеет хотя бы одного соседа в множестве. Это не полная связность, но достаточно для Estate. On-chain проверка в 10 раз дороже, чем off-chain с ZK proof, поэтому для крупных объединений используйте off-chain.
Система прав и операторов
Владелец участка должен контролировать, кто может строить на его земле. Реализуем через bitmap прав: BUILD, SCRIPT, ADMIN.
uint8 public constant RIGHT_BUILD = 1 << 0; uint8 public constant RIGHT_SCRIPT = 1 << 1; uint8 public constant RIGHT_ADMIN = 1 << 3; mapping(uint256 => mapping(address => uint8)) public landOperators; function grantRights(uint256 landId, address operator, uint8 rights) external { require(ownerOf(landId) == msg.sender, "Not owner"); landOperators[landId][operator] |= rights; } function hasRight(uint256 landId, address operator, uint8 right) public view returns (bool) { return ownerOf(landId) == operator || (landOperators[landId][operator] & right) != 0; } Экономика виртуальной земли
District — административная единица, объединяющая участки. Может иметь свой governance и общий доход. Adjacency bonus — участки рядом с landmarks (центр города) дороже. Реализуется через хранение landmark-координат и расчёт расстояния. Например, для каждого соседнего участка проверяется наличие landmark и присваивается бонус. Такая механика создаёт ажиотаж на primary sale, но без контента земля бесполезна. Наш опыт показывает: сначала first-party контент, потом сценарии использования.
Marketplace и торговля
Встроенный marketplace с EIP-2981 роялти позволяет торговать участками. Газ-эффективная реализация с проверкой авторских прав.
struct Listing { uint256 tokenId; uint256 price; address seller; uint256 expiresAt; } mapping(uint256 => Listing) public listings; function buy(uint256 tokenId) external payable { Listing memory listing = listings[tokenId]; require(block.timestamp <= listing.expiresAt, "Listing expired"); require(msg.value >= listing.price, "Insufficient payment"); delete listings[tokenId]; (address royaltyReceiver, uint256 royaltyAmount) = royaltyInfo(tokenId, listing.price); uint256 sellerProceeds = listing.price - royaltyAmount - (listing.price * PLATFORM_FEE / 10000); payable(royaltyReceiver).transfer(royaltyAmount); payable(PLATFORM_TREASURY).transfer(listing.price * PLATFORM_FEE / 10000); payable(listing.seller).transfer(sellerProceeds); _safeTransfer(listing.seller, msg.sender, tokenId, ""); } Что входит в работу над проектом?
- Аудит и оптимизация смарт-контрактов (экономия на gas до 30%).
- Полная документация и тесты (Foundry/Hardhat).
- Интеграция с The Graph или кастомным индексером.
- Передача доступа к контрактам, IPFS и CDN.
- Обучение команды заказчика работе с системой.
- Техническая поддержка на этапе запуска.
Рендеринг карты: 2D vs 3D
| Подход | Технология | Производительность | Сложность |
|---|---|---|---|
| 2D top-down | React + Pixi.js/Konva.js | Высокая (viewport culling) | Средняя |
| 3D world | Three.js/Babylon.js | Средняя (LOD, streaming) | Высокая |
Для первой версии достаточно 2D карты. 3D рендеринг — отдельная итерация, требующая CDN для сцен и системы LOD.
Индексирование данных
On-chain данные неэффективно читать напрямую. Используйте индексер: The Graph или кастомный с PostGIS.
type Land @entity { id: ID! x: Int! y: Int! owner: Bytes! districtId: Int content: LandContent listings: [Listing!]! @derivedFrom(field: "land") transactions: [Transfer!]! @derivedFrom(field: "land") } Стек технологий
| Компонент | Технология |
|---|---|
| Land NFT контракт | ERC-721 + Solidity |
| Estate контракт | ERC-721 + adjacency logic |
| Marketplace | Solidity (кастомный или Seaport) |
| Индексер | The Graph / кастомный + PostGIS |
| 2D карта | React + Pixi.js / Konva.js |
| 3D рендеринг | Three.js / Babylon.js |
| Content storage | IPFS + Pinata / Arweave |
| Сеть | Polygon / Immutable zkEVM |
Сроки и бюджет
MVP (Land NFT, базовый marketplace, 2D карта, загрузка контента) — 2–3 месяца. Полная система с Estate, Districts, 3D рендерингом, системой прав, индексером — 5–7 месяцев. 3D world engine — отдельный проект, 6–12 месяцев. Каждый проект оценивается индивидуально — получите консультацию. Гарантируем безопасность контрактов (аудит обязателен) и опыт в подобных проектах. Команда имеет 7+ лет опыта и 30+ законченных NFT-проектов — оценим ваш проект за 1 день. Свяжитесь с нами, чтобы обсудить детали.







