Skip to content

Enhanced Property Registry Core Functionality & Documentation #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions Clarinet.toml
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
[project]
name = "BitEstates"
description = ""
name = 'BitEstates'
description = ''
authors = []
telemetry = true
cache_dir = "./.cache"

# [contracts.counter]
# path = "contracts/counter.clar"

cache_dir = './.cache'
requirements = []
[contracts.property-registry]
path = 'contracts/property-registry.clar'
clarity_version = 3
epoch = 3.1
[repl.analysis]
passes = ["check_checker"]
check_checker = { trusted_sender = false, trusted_caller = false, callee_filter = false }
passes = ['check_checker']

# Check-checker settings:
# trusted_sender: if true, inputs are trusted after tx_sender has been checked.
# trusted_caller: if true, inputs are trusted after contract-caller has been checked.
# callee_filter: if true, untrusted data may be passed into a private function without a
# warning, if it gets checked inside. This check will also propagate up to the
# caller.
# More informations: https://www.hiro.so/blog/new-safety-checks-in-clarinet
[repl.analysis.check_checker]
strict = false
trusted_sender = false
trusted_caller = false
callee_filter = false
147 changes: 147 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# BitEstates - Decentralized Property Registry

A blockchain-based real estate documentation system leveraging Stacks Layer 2 infrastructure for secure title management and Bitcoin-compliant record keeping.

## Overview

BitEstates revolutionizes property registration through a decentralized smart contract system that combines Bitcoin's security with Stacks L2 efficiency. This solution enables immutable audit trails, standardized metadata management, and granular access controls for real estate assets.

## Key Features

- **Immutable Title Records**: Cryptographic proof of ownership anchored to Bitcoin
- **L2 Efficiency**: Low-cost transactions with Bitcoin finality through Stacks
- **Document Versioning**: Maintain historical records of property modifications
- **Standardized Metadata**:
- 64-character title strings
- 128-character descriptions
- 10-tag classification system
- **Granular Access Control**: Permission-based document viewing system
- **Automatic Audit Trails**: Block-height timestamped registrations

## Technical Specifications

### Data Structures

#### Estate Registry Entry

```clarity
{
title: (string-ascii 64),
owner: principal,
file-size: uint,
registration-block: uint,
description: (string-ascii 128),
tags: (list 10 (string-ascii 32))
}
```

#### Viewing Permissions

```clarity
{
entry-id: uint,
viewer: principal
} => {
access-allowed: bool
}
```

### System Constants

| Constant | Value | Description |
| -------------------- | --------- | --------------------------- |
| registry-admin | tx-sender | Contract deployer |
| registry-entry-count | uint | Total registered properties |

## Core Functions

### 1. Property Registration

**Function:** `register-property`

Registers new property with system-enforced metadata standards:

- Title: 1-64 ASCII characters
- Document Size: 1 byte - 1GB
- Description: 1-128 ASCII characters
- Tags: 1-10 tags (32 chars max each)

```clarity
(register-property
"123 Main St"
2048
"Residential 3BR/2BA"
["residential", "single-family"])
```

### 2. Property Updates

**Function:** `update-property`

Owner-only modification of property details:

```clarity
(update-property
123
"123 Main St - Renovated"
4096
"Updated 4BR/3BA layout"
["renovated", "modern"])
```

### 3. Ownership Transfer

**Function:** `transfer-property`

Secure ownership reassignment:

```clarity
(transfer-property 123 'SP3NEWOWNER000000000000000000000000000)
```

### 4. Property Deletion

**Function:** `delete-property`

Owner-initiated registry removal:

```clarity
(delete-property 123)
```

## Access Control

| Action | Permission Required |
| -------- | ------------------------ |
| Register | None (open registration) |
| Update | Current Owner |
| Transfer | Current Owner |
| Delete | Current Owner |

## Error Codes

| Code | Description | Trigger Conditions |
| ---- | ----------------- | --------------------------- |
| u300 | Admin restriction | Unauthorized admin action |
| u301 | Missing entry | Invalid property ID |
| u302 | Duplicate entry | ID collision |
| u303 | Invalid metadata | Title/desc format violation |
| u304 | File size error | Document >1GB or 0-size |
| u305 | Access denied | Unauthorized modification |
| u306 | Ownership error | Non-owner action attempt |
| u307 | Visibility error | Restricted document access |
| u308 | Tag error | Invalid tag format/quantity |

## Governance

- **Immutable Admin**: Contract deployer set as permanent `registry-admin`
- **Metadata Standards**: Enforced through runtime validation
- **Upgrade Path**: Future versions via new contract deployment

## Contributing

1. Fork repository
2. Create feature branch (`git checkout -b feature/improvement`)
3. Commit changes
4. Push to branch
5. Open Pull Request
208 changes: 208 additions & 0 deletions contracts/property-registry.clar
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
;; BitEstates: Decentralized Property Registry on Stacks L2
;;
;; Summary: Blockchain-based real estate documentation system offering
;; secure title management, immutable audit trails, and Bitcoin-compliant
;; record keeping through Stacks Layer 2 infrastructure.
;;
;; Description: A next-generation property registry solution leveraging
;; Bitcoin's security model and Stacks L2 smart contracts for decentralized
;; title management. Implements granular access controls, document versioning,
;; and standardized metadata schemas while maintaining compliance with
;; blockchain-based property recording standards.

;; System Governance Constants

(define-constant registry-admin tx-sender)
(define-constant err-admin-only (err u300))
(define-constant err-item-not-found (err u301))
(define-constant err-item-already-exists (err u302))
(define-constant err-invalid-title (err u303))
(define-constant err-invalid-document-size (err u304))
(define-constant err-unauthorized-access (err u305))
(define-constant err-not-property-owner (err u306))
(define-constant err-visibility-restricted (err u307))
(define-constant err-tag-format-invalid (err u308))

;; Track total registry entries
(define-data-var registry-entry-count uint u0)

;; Core Registry Storage

;; Primary data store for property documents
(define-map estate-registry
{ entry-id: uint }
{
title: (string-ascii 64),
owner: principal,
file-size: uint,
registration-block: uint,
description: (string-ascii 128),
tags: (list 10 (string-ascii 32))
}
)

;; Permission management for document access
(define-map viewing-permissions
{ entry-id: uint, viewer: principal }
{ access-allowed: bool }
)

;; Utility & Validation Functions

;; Checks if entry with given ID exists
(define-private (entry-exists (entry-id uint))
(is-some (map-get? estate-registry { entry-id: entry-id }))
)

;; Validates property tag format requirements
(define-private (valid-tag (tag (string-ascii 32)))
(and
(> (len tag) u0)
(< (len tag) u33)
)
)

;; Validates the entire set of property tags
(define-private (validate-tags (tag-list (list 10 (string-ascii 32))))
(and
(> (len tag-list) u0)
(<= (len tag-list) u10)
(is-eq (len (filter valid-tag tag-list)) (len tag-list))
)
)

;; Checks if principal is the owner of a property record
(define-private (owns-entry (entry-id uint) (viewer principal))
(match (map-get? estate-registry { entry-id: entry-id })
entry-data (is-eq (get owner entry-data) viewer)
false
)
)

;; Gets document size for specified entry
(define-private (get-document-size (entry-id uint))
(default-to u0
(get file-size
(map-get? estate-registry { entry-id: entry-id })
)
)
)

;; Registry Management Functions

;; Registers a new property document in the system
(define-public (register-property
(property-title (string-ascii 64))
(document-size uint)
(property-details (string-ascii 128))
(property-tags (list 10 (string-ascii 32)))
)
(let
(
(next-id (+ (var-get registry-entry-count) u1))
)
;; Input validation checks
(asserts! (> (len property-title) u0) err-invalid-title)
(asserts! (< (len property-title) u65) err-invalid-title)
(asserts! (> document-size u0) err-invalid-document-size)
(asserts! (< document-size u1000000000) err-invalid-document-size)
(asserts! (> (len property-details) u0) err-invalid-title)
(asserts! (< (len property-details) u129) err-invalid-title)
(asserts! (validate-tags property-tags) err-tag-format-invalid)

;; Create the property record
(map-insert estate-registry
{ entry-id: next-id }
{
title: property-title,
owner: tx-sender,
file-size: document-size,
registration-block: stacks-block-height,
description: property-details,
tags: property-tags
}
)

;; Set initial access permissions
(map-insert viewing-permissions
{ entry-id: next-id, viewer: tx-sender }
{ access-allowed: true }
)

;; Update counter and return success
(var-set registry-entry-count next-id)
(ok next-id)
)
)

;; Updates property information for an existing entry
(define-public (update-property
(entry-id uint)
(new-title (string-ascii 64))
(new-size uint)
(new-details (string-ascii 128))
(new-tags (list 10 (string-ascii 32)))
)
(let
(
(entry-data (unwrap! (map-get? estate-registry { entry-id: entry-id }) err-item-not-found))
)
;; Validate ownership and input parameters
(asserts! (entry-exists entry-id) err-item-not-found)
(asserts! (is-eq (get owner entry-data) tx-sender) err-not-property-owner)
(asserts! (> (len new-title) u0) err-invalid-title)
(asserts! (< (len new-title) u65) err-invalid-title)
(asserts! (> new-size u0) err-invalid-document-size)
(asserts! (< new-size u1000000000) err-invalid-document-size)
(asserts! (> (len new-details) u0) err-invalid-title)
(asserts! (< (len new-details) u129) err-invalid-title)
(asserts! (validate-tags new-tags) err-tag-format-invalid)

;; Update the property record with new information
(map-set estate-registry
{ entry-id: entry-id }
(merge entry-data {
title: new-title,
file-size: new-size,
description: new-details,
tags: new-tags
})
)
(ok true)
)
)

;; Transfers property ownership to another principal
(define-public (transfer-property (entry-id uint) (new-owner principal))
(let
(
(entry-data (unwrap! (map-get? estate-registry { entry-id: entry-id }) err-item-not-found))
)
;; Verify caller is the current owner
(asserts! (entry-exists entry-id) err-item-not-found)
(asserts! (is-eq (get owner entry-data) tx-sender) err-not-property-owner)

;; Update ownership
(map-set estate-registry
{ entry-id: entry-id }
(merge entry-data { owner: new-owner })
)
(ok true)
)
)

;; Removes a property record from the registry
(define-public (delete-property (entry-id uint))
(let
(
(entry-data (unwrap! (map-get? estate-registry { entry-id: entry-id }) err-item-not-found))
)
;; Ownership verification
(asserts! (entry-exists entry-id) err-item-not-found)
(asserts! (is-eq (get owner entry-data) tx-sender) err-not-property-owner)

;; Remove the property record
(map-delete estate-registry { entry-id: entry-id })
(ok true)
)
)
Loading