Кілька років тому, коли 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.







