Кілька років тому, коли Decentraland запустила LAND, координати парцелей зберігалися в одному контракті. Сучасні метавсесвіти вимагають гнучких рішень: on-chain оренда, аукціони, adjacency premium. Ми створюємо торгові майданчики для віртуальної нерухомості, які підтримують Decentraland LAND, Sandbox LAND, Otherside Otherdeed та власні L2-рішення. Кожен проєкт потребує власного майданчика для вторинної торгівлі, оренди та забудови. Розробка маркетплейсу віртуальної нерухомості — це перетин інфраструктури NFT marketplace, on-chain rental механік та spatial data management. Наш досвід включає понад 5 проєктів у цій області, і ми гарантуємо аудит смарт-контрактів.
Технічна специфіка порівняно з generic NFT marketplace: парцелі мають координати (x, y), можливе сусідство та adjacency бонуси, оренда тимчасова з поверненням прав, забудова створює metadata relationship між LAND NFT та content NFT. Ці нюанси вимагають нестандартних рішень: від coordinate-based tokenId до тимчасового делегування прав через ERC-4907.
Як працює on-chain оренда віртуальної нерухомості?
ERC-4907: Rentable NFT стандарт
Оренда віртуальної нерухомості — значний use case: власник зберігає LAND як інвестицію, орендар використовує для забудови/заходів. Необхідно розділити ownership (NFT у власника) та usage rights (у орендаря). ERC-4907 додає роль user до ERC-721 — тимчасовий користувач з expiry timestamp. Контракти можуть перевіряти userOf(tokenId) замість ownerOf для доступу.
contract RentalMarketplace { struct RentalOffer { uint256 tokenId; address landContract; uint256 pricePerDay; uint256 minDays; uint256 maxDays; address paymentToken; // ERC-20 або address(0) для native bool active; } mapping(bytes32 => RentalOffer) public rentalOffers; function createRentalOffer( uint256 tokenId, address landContract, uint256 pricePerDay, uint256 minDays, uint256 maxDays, address paymentToken ) external { require(IERC721(landContract).ownerOf(tokenId) == msg.sender, "Not owner"); bytes32 offerId = keccak256(abi.encode(tokenId, landContract, msg.sender, block.timestamp)); rentalOffers[offerId] = RentalOffer({ tokenId: tokenId, landContract: landContract, pricePerDay: pricePerDay, minDays: minDays, maxDays: maxDays, paymentToken: paymentToken, active: true }); } function rent(bytes32 offerId, uint256 days) external payable { RentalOffer storage offer = rentalOffers[offerId]; require(offer.active, "Offer not active"); require(days >= offer.minDays && days <= offer.maxDays, "Invalid duration"); uint256 totalCost = offer.pricePerDay * days; uint256 expiry = block.timestamp + days * 1 days; // Оплата if (offer.paymentToken == address(0)) { require(msg.value >= totalCost, "Insufficient payment"); } else { IERC20(offer.paymentToken).safeTransferFrom(msg.sender, address(this), totalCost); } // Встановлюємо user через ERC-4907 IERC4907(offer.landContract).setUser(offer.tokenId, msg.sender, uint64(expiry)); // Виплачуємо власнику (minus protocol fee) uint256 fee = totalCost * PROTOCOL_FEE_BPS / 10000; _transferPayment(offer.paymentToken, IERC721(offer.landContract).ownerOf(offer.tokenId), totalCost - fee); emit Rented(offerId, msg.sender, days, expiry); } } Collateral rental (без ERC-4907)
Якщо LAND контракт не підтримує ERC-4907: тимчасова передача NFT з collateral. Орендар вносить заставу (рівну або більшу за вартість LAND), NFT передається, після закінчення — автоматичне повернення через keeper або manual claim. Проблема: орендодавець втрачає фізичне володіння NFT на час оренди (хоча має право повернути). Ризик: орендар продає NFT незважаючи на collateral. Рішення: NFT передається в escrow контракт, не орендарю.
Які механіки marketplace необхідні?
Listing та аукціони
enum SaleType { FIXED_PRICE, ENGLISH_AUCTION, DUTCH_AUCTION } struct Listing { uint256 tokenId; address seller; SaleType saleType; address paymentToken; uint256 startPrice; uint256 endPrice; // для Dutch auction: кінцева ціна uint256 startTime; uint256 endTime; uint256 highestBid; // для English auction address highestBidder; } Dutch Auction особливо релевантний для первинного продажу LAND: ціна починається високо, автоматично знижується до резервної. Усуває газову війну при mint — порівняння: Dutch auction знижує комісії на 40% порівняно з fixed-price mint.
English Auction для вторинного ринку рідкісних Estate: бідинг з outbid захистом (мінімальне підвищення ставки на X%).
Royalties та fee структура
ERC-2981 для on-chain royalties. Стандартна структура маркетплейсу віртуальної нерухомості:
| Fee | Отримувач | Розмір |
|---|---|---|
| Marketplace fee | Protocol treasury | 2-2.5% |
| Creator royalty | Оригінальний творець метавсесвіту | 2.5-5% |
| Referral | Якщо є referral program | 0.5-1% |
| Seller | Власник LAND | Залишок |
Royalties для віртуальної нерухомості — контроверсійна тема. Платформи типу Blur підірвали enforcement. Рішення: royalties enforcement через контракт (не залежить від marketplace), або royalty-free модель з revenue sharing іншого типу.
Що таке adjacency premium?
Унікальна риса земельних маркетплейсів: сусідні парцелі коштують більше разом, ніж окремо. Алгоритм пошуку adjacency перевіряє координати на суміжність за кардинальними та діагональними напрямками. Frontend відображає на карті виділені суміжні лоти при hover на один — користувач бачить потенційні bundle покупки. Типова премія за формування estate становить 15-30% від суми окремих ділянок. Наприклад, дві сусідні ділянки окремо коштують 10 ETH кожна, а при об'єднанні в estate їх сумарна ціна — 23 ETH замість 20, тобто премія 3 ETH (15%).
LAND NFT: специфіка даних
Coordinate system on-chain
Кожна парцель — NFT з координатами в сітці. Стандартний підхід: tokenId кодує координати.
contract VirtualLand is ERC721 { struct Parcel { int256 x; int256 y; address tenant; // поточний орендар (якщо здано) uint256 leaseExpiry; // timestamp закінчення оренди string contentURI; // що побудовано на ділянці uint8 zoneType; // 0=residential, 1=commercial, 2=plaza } mapping(uint256 => Parcel) public parcels; mapping(int256 => mapping(int256 => uint256)) public coordToTokenId; // coordToTokenId[x][y] = tokenId int256 public constant GRID_MIN = -150; int256 public constant GRID_MAX = 150; // tokenId = унікальний індекс з координат function coordsToTokenId(int256 x, int256 y) public pure returns (uint256) { // Зсуваємо в невід'ємні значення uint256 ux = uint256(x - GRID_MIN); uint256 uy = uint256(y - GRID_MIN); uint256 size = uint256(GRID_MAX - GRID_MIN + 1); return ux * size + uy; } function tokenIdToCoords(uint256 tokenId) public pure returns (int256 x, int256 y) { uint256 size = uint256(GRID_MAX - GRID_MIN + 1); x = int256(tokenId / size) + GRID_MIN; y = int256(tokenId % size) + GRID_MIN; } } Estate: об'єднані парцелі
Estate = кілька суміжних парцелей, об'єднаних в один актив. Це значимо: велика забудована ділянка цінніша за суму частин. Механіка:
contract EstateRegistry is ERC721 { struct Estate { uint256[] parcels; // масив tokenId вхідних парцелей address landContract; } mapping(uint256 => Estate) public estates; // парцель → estate (якщо входить в estate) mapping(uint256 => uint256) public parcelToEstate; function createEstate(uint256[] calldata parcelIds) external returns (uint256 estateId) { // Перевіряємо adjacency require(_areAdjacent(parcelIds), "Parcels must be adjacent"); // Перевіряємо ownership всіх парцелей for (uint i = 0; i < parcelIds.length; i++) { require(landNft.ownerOf(parcelIds[i]) == msg.sender, "Not owner"); } estateId = ++_estateIdCounter; // Передаємо парцелі в escrow цього контракту for (uint i = 0; i < parcelIds.length; i++) { landNft.transferFrom(msg.sender, address(this), parcelIds[i]); parcelToEstate[parcelIds[i]] = estateId; } estates[estateId] = Estate({ parcels: parcelIds, landContract: address(landNft) }); _mint(msg.sender, estateId); } } Spatial Data та Map Interface
Інтерактивна карта — основний UI майданчика. Вимоги: відображення тисяч парцелей з кольоровим кодуванням (продається, здається, зайнято), плавний zoom/pan, клік на парцель → детальна інформація.
WebGL та deck.gl — найбільш продуктивні варіанти для spatial rendering тисяч об'єктів. deck.gl (Uber) оптимізований для геоданих і працює з WebGL.
import { DeckGL } from '@deck.gl/react' import { ScatterplotLayer } from '@deck.gl/layers' const parcelLayer = new ScatterplotLayer({ data: parcels, getPosition: (d) => [d.x * PARCEL_SIZE, d.y * PARCEL_SIZE, 0], getFillColor: (d) => { if (d.forSale) return [0, 200, 100] // зелений — на продаж if (d.forRent) return [0, 100, 200] // синій — в оренду if (d.hasContent) return [150, 100, 200] // фіолетовий — забудований return [100, 100, 100] // сірий — пусто }, getRadius: PARCEL_SIZE / 2, pickable: true, onClick: ({ object }) => setSelectedParcel(object), }) Content Layer: що будують на LAND
Забудова LAND — окремий шар даних. Стандартні формати: Decentraland SDK scene (Babylon.js-based), GLTF/GLB assets, iframe-based content. Content URI зберігається в LAND NFT metadata. При зміні забудови власник оновлює contentURI через setContentURI(tokenId, newURI). Це on-chain транзакція, історія змін зберігається.
Аналітика та price discovery
Майданчик без аналітики — не конкурентоспроможний. Необхідний мінімум: floor price по зонах, price history, volume, heatmap активності, rental yield calculator. Дані індексуються через The Graph subgraph для on-chain подій та PostgreSQL з PostGIS для off-chain метаданих і просторових запитів.
Як створити маркетплейс віртуальної нерухомості: поетапне керівництво
- Product design (1-2 тижні). Карта світу, зонування, модель первинного продажу, rental модель, fee структура.
- Смарт-контракти (4-6 тижнів). LAND NFT, Estate контракт, Rental marketplace, Sale marketplace. Обов'язковий аудит.
- Backend та indexer (3-4 тижні). Subgraph, REST/GraphQL API, spatial queries, price analytics.
- Map Frontend (4-6 тижнів). Інтерактивна карта, parcel detail page, listing/rental UI, analytics dashboard.
- 3D Content preview (2-3 тижні, опціонально). GLTF preview для забудованих парцелей.
- Тестування та launch. End-to-end тест, навантажувальний тест карти.
MVP без Estate та 3D content займе 3-4 місяці. Повна версія з Estate, rental, аналітикою та 3D preview — 6-8 місяців.
Стек розробки
| Компонент | Технологія |
|---|---|
| LAND NFT | Solidity ERC-721 + ERC-4907 |
| Estate контракт | Solidity з adjacency validation |
| Rental контракт | Solidity + ERC-4907 |
| Marketplace контракт | Solidity + ERC-2981 |
| Indexer | The Graph (subgraph) |
| Spatial DB | PostgreSQL + PostGIS |
| Map frontend | deck.gl / Mapbox GL JS + React |
| 3D preview | Three.js / Babylon.js |
| Backend API | Node.js + Fastify |
| Storage | IPFS (Pinata) + Arweave |
Замовте розробку під ключ — наші інженери з досвідом понад 5 років у blockchain оцінять ваш проєкт і запропонують оптимальне рішення.
Що входить в роботу
- Розробка та аудит смарт-контрактів (Solidity, Foundry)
- Інтеграція з The Graph для індексації
- Реалізація інтерактивної карти (deck.gl)
- Backend API та база даних (PostgreSQL + PostGIS)
- Документація з інтеграції та деплою
- Технічна підтримка протягом 1 місяця після запуску
Отримайте консультацію з розробки маркетплейсу віртуальної нерухомості. Власники LAND економлять до 30% при bundle-продажу завдяки adjacency premium.







