לפני כמה שנים, כשדצ׳נטרלנד השיקה את LAND, קואורדינטות החלקות אוחסנו בחוזה אחד. מטאוורסים מודרניים דורשים פתרונות גמישים: השכרות על-רשת, מכירות פומביות, פרמיית סמיכות. אנו בונים שווקים לנכסי נדל״ן וירטואליים התומכים ב-Decentraland LAND, Sandbox LAND, Otherside Otherdeed, ופתרונות L2 מותאמים אישית. כל פרויקט זקוק לפלטפורמת מסחר משני, השכרה ופיתוח משלו. פיתוח שוק נדל״ן וירטואלי הוא המפגש בין תשתית שוק NFT, מכניקת השכרה על-רשת, וניהול נתונים מרחביים. הניסיון שלנו כולל מעל 5 פרויקטים בתחום זה, ואנו מבטיחים ביקורת חוזים חכמים.
ההבדלים הטכניים לעומת שוק NFT כללי: לחלקות יש קואורדינטות (x, y), סמיכות ובונוסי סמיכות אפשריים, השכרה היא זמנית עם החזרת זכויות, ופיתוח יוצר קשרי מטא-דאטה בין NFT של LAND ל-NFT של תוכן. ניואנסים אלה דורשים פתרונות לא סטנדרטיים: מ-tokenId מבוסס קואורדינטות ועד האצלת זכויות זמנית דרך ERC-4907.
איך עובדת השכרה על-רשת של נדל״ן וירטואלי
ERC-4907: תקן NFT להשכרה
השכרת קרקע היא מקרה שימוש משמעותי: הבעלים מחזיק ב-LAND כהשקעה, השוכר משתמש בו לפיתוח/אירועים. יש צורך להפריד בין בעלות (NFT עם בעלים) לבין זכויות שימוש (עם שוכר). ERC-4907 מוסיף תפקיד user ל-ERC-721 — משתמש זמני עם חותמת זמן לתפוגה. חוזים יכולים לבדוק 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);
}
} השכרה עם בטחון (ללא ERC-4907)
אם חוזה ה-LAND אינו תומך ב-ERC-4907: העברת NFT זמנית עם בטחון. השוכר מפקיד בטחון (שווה או גדול מערך ה-LAND), ה-NFT מועבר, ועם התפוגה הוא מוחזר אוטומטית דרך keeper או תביעה ידנית. בעיה: הבעלים מאבד את החזקה הפיזית ב-NFT במהלך תקופת ההשכרה (למרות שיש לו זכות להחזירו). סיכון: השוכר מוכר את ה-NFT למרות הבטחון. פתרון: ה-NFT מועבר לחוזה נאמנות (escrow), לא לשוכר.
אילו מכניקות שוק נדרשות?
רשימה ומכירות פומביות
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;
}מכירה פומבית הולנדית רלוונטית במיוחד למכירות ראשוניות של LAND: המחיר מתחיל גבוה ויורד אוטומטית למחיר רצפה. זה מבטל מלחמות גז במהלך mint — השוואה: מכירה הולנדית מפחיתה עמלות ב-40% לעומת mint במחיר קבוע.
מכירה פומבית אנגלית לשוק המשני של אחוזות נדירות: הצעות עם הגנה מפני הצעות יתר (הפרש מינימלי של X% בין הצעות).
תמלוגים ומבנה עמלות
ERC-2981 לתמלוגים על-רשת. מבנה עמלות סטנדרטי לשוק נדל״ן וירטואלי:
| עמלה | נמען | סכום |
|---|---|---|
| עמלת שוק | אוצר הפרוטוקול | 2-2.5% |
| תמלוג יוצר | היוצר המקורי של המטאוורס | 2.5-5% |
| עמלת הפניה | אם קיימת תוכנית הפניות | 0.5-1% |
| מוכר | בעל ה-LAND | היתרה |
תמלוגים לנדל״ן וירטואלי הם נושא שנוי במחלוקת. פלטפורמות כמו Blur ערערו את האכיפה. פתרון: אכיפת תמלוגים דרך החוזה (בלתי תלוי בשוק), או מודל ללא תמלוגים עם חלוקת הכנסות חלופית.
מהי פרמיית סמיכות?
תכונה ייחודית של שווקי קרקע: חלקות סמוכות שוות יותר יחד מאשר בנפרד. אלגוריתם חיפוש הסמיכות בודק קואורדינטות לרציפות קרדינלית ואלכסונית. הממשק מציג חלקות סמוכות מודגשות בעת ריחוף על אחת — המשתמש רואה רכישות חבילה פוטנציאליות. פרמיה טיפוסית ליצירת אחוזה היא 15-30% מסכום החלקות הבודדות. לדוגמה, שתי חלקות סמוכות שוות בנפרד 10 ETH כל אחת, אך בשילוב כאחוזה מחירן הכולל הוא 23 ETH במקום 20, פרמיה של 3 ETH (15%).
LAND NFT: פרטי נתונים
מערכת קואורדינטות על-רשת
כל חלקה היא 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;
}
} אחוזה: חלקות מאוחדות
אחוזה = מספר חלקות סמוכות המאוחדות לנכס אחד. זה משמעותי: חלקה גדולה ומפותחת שווה יותר מסכום חלקיה. מכניקה:
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);
}
} נתונים מרחביים וממשק מפה
מפה אינטראקטיבית — ממשק המשתמש הראשי של השוק. דרישות: הצגת אלפי חלקות עם קידוד צבע (למכירה, להשכרה, תפוסות), זום/פאן חלק, לחיצה על חלקה → מידע מפורט.
WebGL ו-deck.gl — האפשרויות היעילות ביותר לעיבוד מרחבי של אלפי אובייקטים. 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),
}) שכבת תוכן: מה נבנה על LAND
פיתוח קרקע הוא שכבת נתונים נפרדת. פורמטים סטנדרטיים: סצנת Decentraland SDK (מבוססת Babylon.js), נכסי GLTF/GLB, תוכן מבוסס iframe. URI התוכן מאוחסן במטא-דאטה של NFT ה-LAND. כאשר הפיתוח משתנה, הבעלים מעדכן את contentURI דרך 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); } } . זו עסקה על-רשת, והיסטוריית השינויים נשמרת.
אנליטיקה וגילוי מחירים
שוק ללא אנליטיקה אינו תחרותי. המינימום הנדרש: מחיר רצפה לפי אזורים, היסטוריית מחירים, נפח, מפת חום של פעילות, מחשבון תשואת השכרה. נתונים מתועדים דרך The Graph subgraph לאירועים על-רשת ו-PostgreSQL עם PostGIS למטא-דאטה מחוץ לרשת ושאילתות מרחביות.
איך לבנות שוק נדל״ן וירטואלי: מדריך שלב-אחר-שלב
- עיצוב מוצר (1-2 שבועות). מפת עולם, אזורים, מודל מכירה ראשונית, מודל השכרה, מבנה עמלות.
- חוזים חכמים (4-6 שבועות). LAND NFT, חוזה אחוזה, שוק השכרה, שוק מכירה. ביקורת חובה.
- בקאנד ואינדקסר (3-4 שבועות). Subgraph, REST/GraphQL API, שאילתות מרחביות, אנליטיקת מחירים.
- פרונטאנד מפה (4-6 שבועות). מפה אינטראקטיבית, דף פרטי חלקה, ממשק רישום/השכרה, לוח אנליטיקה.
- תצוגה מקדימה של תוכן תלת-ממדי (2-3 שבועות, אופציונלי). תצוגת GLTF לחלקות מפותחות.
- בדיקות והשקה. בדיקת end-to-end, בדיקת עומס של המפה.
MVP ללא אחוזה ותוכן תלת-ממדי לוקח 3-4 חודשים. גרסה מלאה עם אחוזה, השכרה, אנליטיקה ותצוגה תלת-ממדית — 6-8 חודשים.
ערימת פיתוח
| רכיב | טכנולוגיה |
|---|---|
| LAND NFT | Solidity ERC-721 + ERC-4907 |
| חוזה אחוזה | Solidity עם אימות סמיכות |
| חוזה השכרה | Solidity + ERC-4907 |
| חוזה שוק | Solidity + ERC-2981 |
| אינדקסר | The Graph (subgraph) |
| מסד נתונים מרחבי | PostgreSQL + PostGIS |
| פרונטאנד מפה | deck.gl / Mapbox GL JS + React |
| תצוגה תלת-ממדית | Three.js / Babylon.js |
| API בקאנד | Node.js + Fastify |
| אחסון | IPFS (Pinata) + Arweave |
הזמינו פיתוח turnkey — המהנדסים שלנו עם ניסיון של 5+ שנים בבלוקצ׳יין יעריכו את הפרויקט שלכם ויציעו את הפתרון האופטימלי.
מה כלול בעבודה
- פיתוח וביקורת חוזים חכמים (Solidity, Foundry)
- אינטגרציה עם The Graph לאינדוקס
- יישום מפה אינטראקטיבית (deck.gl)
- API בקאנד ומסד נתונים (PostgreSQL + PostGIS)
- תיעוד אינטגרציה והתקנה
- תמיכה טכנית למשך חודש לאחר ההשקה
קבלו ייעוץ על פיתוח שוק נדל״ן וירטואלי. בעלי LAND חוסכים עד 30% במכירות חבילה בזכות פרמיית סמיכות.







