Разработка системы реестра собственности на блокчейне

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы реестра собственности на блокчейне
Сложная
от 1 недели до 3 месяцев
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1224
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    859
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1069
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    829

Разработка системы реестра собственности на блокчейне

Традиционные реестры недвижимости — медленные, непрозрачные, уязвимые к мошенничеству и сложные для международных транзакций. Блокчейн-реестр решает конкретные проблемы: прозрачная история владения, атомарные сделки (deeds delivery vs payment одновременно), fractional ownership через токенизацию, и программируемые условия передачи (автоматическое исполнение при выполнении условий).

Правовой контекст: первая сложность

Ключевое ограничение: в большинстве юрисдикций право собственности на недвижимость создаётся государственной регистрацией, не записью в блокчейне. Блокчейн-реестр должен либо быть официальным (государственный проект), либо работать как Layer 2 поверх официального реестра (отслеживает транзакции, упрощает процесс, но финальная регистрация в Росреестре/Кадастре).

Исключение: цифровые активы (виртуальная недвижимость в метавёрсах, mineral rights в некоторых юрисдикциях, securities-based fractional ownership).

Для реального имущества — паттерн "blockchain as notary": фиксируем факты и документы, но правовая сила за официальными органами.

Архитектура property registry

Property NFT

Каждый объект недвижимости — уникальный NFT. Metadata содержит кадастровый номер, адрес, площадь, ссылку на документы в IPFS.

contract PropertyRegistry is ERC721URIStorage, AccessControl {
    bytes32 public constant REGISTRAR_ROLE = keccak256("REGISTRAR_ROLE");
    bytes32 public constant NOTARY_ROLE = keccak256("NOTARY_ROLE");
    
    struct Property {
        string cadastralNumber;  // государственный кадастровый номер
        string propertyType;     // "RESIDENTIAL", "COMMERCIAL", "LAND"
        string address_;
        uint256 area;            // площадь в кв.дм (избегаем float)
        bytes32 documentsHash;   // IPFS hash пакета документов
        uint256 registeredAt;
        uint256 lastTransferAt;
        bool encumbered;         // залог, арест
        string encumbranceDetails;
    }
    
    // tokenId => Property
    mapping(uint256 => Property) public properties;
    
    // cadastralNumber => tokenId
    mapping(string => uint256) public cadastralToToken;
    
    // tokenId => liens (залоги и обременения)
    mapping(uint256 => Lien[]) public propertyLiens;
    
    struct Lien {
        address creditor;
        uint256 amount;
        uint256 expiresAt;
        string description;
        bool active;
    }
    
    event PropertyRegistered(uint256 indexed tokenId, string cadastralNumber, address owner);
    event PropertyTransferred(uint256 indexed tokenId, address from, address to, uint256 price);
    event LienAdded(uint256 indexed tokenId, address creditor, uint256 amount);
    
    function registerProperty(
        address owner,
        string calldata cadastralNumber,
        string calldata propertyType,
        string calldata address_,
        uint256 area,
        bytes32 documentsHash,
        string calldata metadataURI
    ) external onlyRole(REGISTRAR_ROLE) returns (uint256 tokenId) {
        require(cadastralToToken[cadastralNumber] == 0, "Already registered");
        
        tokenId = uint256(keccak256(abi.encodePacked(cadastralNumber)));
        
        properties[tokenId] = Property({
            cadastralNumber: cadastralNumber,
            propertyType: propertyType,
            address_: address_,
            area: area,
            documentsHash: documentsHash,
            registeredAt: block.timestamp,
            lastTransferAt: block.timestamp,
            encumbered: false,
            encumbranceDetails: ""
        });
        
        cadastralToToken[cadastralNumber] = tokenId;
        _safeMint(owner, tokenId);
        _setTokenURI(tokenId, metadataURI);
        
        emit PropertyRegistered(tokenId, cadastralNumber, owner);
        return tokenId;
    }
    
    // Обременение запрещает передачу (залог, арест)
    function addLien(
        uint256 tokenId,
        address creditor,
        uint256 amount,
        uint256 duration,
        string calldata description
    ) external onlyRole(NOTARY_ROLE) {
        propertyLiens[tokenId].push(Lien({
            creditor: creditor,
            amount: amount,
            expiresAt: block.timestamp + duration,
            description: description,
            active: true
        }));
        
        properties[tokenId].encumbered = true;
        emit LienAdded(tokenId, creditor, amount);
    }
    
    // Проверяем обременения перед передачей
    function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize) 
        internal override 
    {
        super._beforeTokenTransfer(from, to, tokenId, batchSize);
        
        if (from != address(0)) { // не mint
            require(!hasActiveLiens(tokenId), "Property has active liens");
        }
    }
    
    function hasActiveLiens(uint256 tokenId) public view returns (bool) {
        Lien[] memory liens = propertyLiens[tokenId];
        for (uint i = 0; i < liens.length; i++) {
            if (liens[i].active && block.timestamp < liens[i].expiresAt) return true;
        }
        return false;
    }
}

Escrow для сделок

Атомарная сделка: покупатель вносит деньги в escrow, при подтверждении всех условий — NFT передаётся покупателю, деньги продавцу одновременно.

contract PropertyEscrow {
    enum EscrowState { CREATED, FUNDED, CONDITIONS_MET, COMPLETED, DISPUTED, REFUNDED }
    
    struct EscrowDeal {
        uint256 propertyTokenId;
        address seller;
        address buyer;
        address notary;          // нотариус как арбитр
        uint256 price;           // в стейблкоине (USDC)
        IERC20 paymentToken;
        EscrowState state;
        uint256 createdAt;
        uint256 completionDeadline;
        bytes32[] requiredDocuments; // хеши документов для проверки
        mapping(bytes32 => bool) submittedDocuments;
    }
    
    PropertyRegistry public registry;
    
    mapping(uint256 => EscrowDeal) public deals;
    uint256 private _nextDealId;
    
    function createDeal(
        uint256 propertyTokenId,
        address buyer,
        address notary,
        uint256 price,
        address paymentToken,
        uint256 deadline,
        bytes32[] calldata requiredDocs
    ) external returns (uint256 dealId) {
        require(registry.ownerOf(propertyTokenId) == msg.sender, "Not owner");
        require(!registry.hasActiveLiens(propertyTokenId), "Property encumbered");
        
        dealId = _nextDealId++;
        EscrowDeal storage deal = deals[dealId];
        deal.propertyTokenId = propertyTokenId;
        deal.seller = msg.sender;
        deal.buyer = buyer;
        deal.notary = notary;
        deal.price = price;
        deal.paymentToken = IERC20(paymentToken);
        deal.state = EscrowState.CREATED;
        deal.completionDeadline = block.timestamp + deadline;
        deal.requiredDocuments = requiredDocs;
        
        // Блокируем NFT в контракте
        registry.transferFrom(msg.sender, address(this), propertyTokenId);
        
        emit DealCreated(dealId, propertyTokenId, msg.sender, buyer);
    }
    
    function fundEscrow(uint256 dealId) external {
        EscrowDeal storage deal = deals[dealId];
        require(msg.sender == deal.buyer, "Not buyer");
        require(deal.state == EscrowState.CREATED, "Wrong state");
        
        deal.paymentToken.transferFrom(msg.sender, address(this), deal.price);
        deal.state = EscrowState.FUNDED;
    }
    
    // Нотариус подтверждает что все документы проверены
    function completeDeal(uint256 dealId) external {
        EscrowDeal storage deal = deals[dealId];
        require(msg.sender == deal.notary, "Not notary");
        require(deal.state == EscrowState.FUNDED, "Not funded");
        
        // Атомарная сделка
        registry.transferFrom(address(this), deal.buyer, deal.propertyTokenId);
        deal.paymentToken.transfer(deal.seller, deal.price);
        deal.state = EscrowState.COMPLETED;
        
        emit DealCompleted(dealId, deal.propertyTokenId, deal.buyer, deal.seller);
    }
    
    function refundExpiredDeal(uint256 dealId) external {
        EscrowDeal storage deal = deals[dealId];
        require(block.timestamp > deal.completionDeadline, "Not expired");
        require(deal.state == EscrowState.FUNDED, "Wrong state");
        
        deal.paymentToken.transfer(deal.buyer, deal.price);
        registry.transferFrom(address(this), deal.seller, deal.propertyTokenId);
        deal.state = EscrowState.REFUNDED;
    }
}

Fractional ownership

Токенизация доли в недвижимости — для инвестиционных объектов:

contract FractionalProperty is ERC20 {
    uint256 public propertyTokenId;
    PropertyRegistry public registry;
    
    uint256 public totalShares = 1_000_000; // 1M долей
    
    // Аренда распределяется пропорционально долям
    mapping(address => uint256) public unclaimedRent;
    uint256 public accumulatedRentPerShare;
    
    function distributeRent(uint256 amount) external onlyManager {
        require(totalSupply() > 0, "No shareholders");
        accumulatedRentPerShare += amount * 1e18 / totalSupply();
        paymentToken.transferFrom(msg.sender, address(this), amount);
    }
    
    function claimRent() external {
        uint256 owed = balanceOf(msg.sender) * accumulatedRentPerShare / 1e18 
                      - unclaimedRent[msg.sender];
        unclaimedRent[msg.sender] += owed;
        paymentToken.transfer(msg.sender, owed);
    }
}

История транзакций и цепочка владения

On-chain история — ключевое преимущество. The Graph subgraph индексирует все Transfer события и строит полную цепочку владения с ценами сделок.

Для property history API:

query PropertyHistory($tokenId: String!) {
  propertyTransfers(where: { tokenId: $tokenId }, orderBy: timestamp) {
    from { id }
    to { id }
    timestamp
    transactionHash
    price
    notary { id name }
  }
  liens(where: { propertyId: $tokenId }) {
    creditor { id }
    amount
    expiresAt
    active
    description
  }
}

Стек

Компонент Технология
Property NFT ERC-721 + OpenZeppelin
Fractional shares ERC-20
Escrow кастомный контракт
Documents IPFS / Arweave (permanent storage)
Indexing The Graph
Frontend React + wagmi + Mapbox (карта объектов)
Notary portal Next.js admin panel
Payment USDC / USDT (стейблкоины)

Сроки разработки

Фаза 1 (3-4 нед): Property Registry контракт, базовые функции регистрации и обременений.

Фаза 2 (2-3 нед): Escrow контракт, notary flow, атомарные сделки.

Фаза 3 (2-3 нед): Fractional ownership токены, rent distribution.

Фаза 4 (3-4 нед): The Graph subgraph, frontend (property browser, ownership history, transaction UI).

Фаза 5 (1-2 нед): Аудит смарт-контрактов (escrow управляет реальными деньгами).

Полная система: 3-4 месяца. MVP без fractional ownership и Mapbox: 6-8 недель.