Несколько лет назад, когда 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.







