From 3f54ddfa2cf1b17a11e41d731d83bd07aae5002c Mon Sep 17 00:00:00 2001 From: Fishon Amos Date: Mon, 7 Oct 2024 12:48:50 +0100 Subject: [PATCH 1/5] feat: fix and deploy regsitry --- land_registry/Scarb.lock | 105 ------------------ land_registry/Scarb.toml | 19 +++- .../src/contracts/LandRegistry.cairo | 61 +++++----- land_registry/src/traits/ILandNFT.cairo | 23 ++-- 4 files changed, 66 insertions(+), 142 deletions(-) diff --git a/land_registry/Scarb.lock b/land_registry/Scarb.lock index 366a208a..51488a1a 100644 --- a/land_registry/Scarb.lock +++ b/land_registry/Scarb.lock @@ -4,108 +4,3 @@ version = 1 [[package]] name = "landver" version = "0.1.0" -dependencies = [ - "openzeppelin", -] - -[[package]] -name = "openzeppelin" -version = "0.17.0" -source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.17.0#bf5d02c25c989ccc24f3ab42ec649617d3f21289" -dependencies = [ - "openzeppelin_access", - "openzeppelin_account", - "openzeppelin_finance", - "openzeppelin_governance", - "openzeppelin_introspection", - "openzeppelin_merkle_tree", - "openzeppelin_presets", - "openzeppelin_security", - "openzeppelin_token", - "openzeppelin_upgrades", - "openzeppelin_utils", -] - -[[package]] -name = "openzeppelin_access" -version = "0.17.0" -source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.17.0#bf5d02c25c989ccc24f3ab42ec649617d3f21289" -dependencies = [ - "openzeppelin_introspection", - "openzeppelin_utils", -] - -[[package]] -name = "openzeppelin_account" -version = "0.17.0" -source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.17.0#bf5d02c25c989ccc24f3ab42ec649617d3f21289" -dependencies = [ - "openzeppelin_introspection", - "openzeppelin_utils", -] - -[[package]] -name = "openzeppelin_finance" -version = "0.17.0" -source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.17.0#bf5d02c25c989ccc24f3ab42ec649617d3f21289" -dependencies = [ - "openzeppelin_access", - "openzeppelin_token", -] - -[[package]] -name = "openzeppelin_governance" -version = "0.17.0" -source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.17.0#bf5d02c25c989ccc24f3ab42ec649617d3f21289" -dependencies = [ - "openzeppelin_access", - "openzeppelin_introspection", -] - -[[package]] -name = "openzeppelin_introspection" -version = "0.17.0" -source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.17.0#bf5d02c25c989ccc24f3ab42ec649617d3f21289" - -[[package]] -name = "openzeppelin_merkle_tree" -version = "0.17.0" -source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.17.0#bf5d02c25c989ccc24f3ab42ec649617d3f21289" - -[[package]] -name = "openzeppelin_presets" -version = "0.17.0" -source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.17.0#bf5d02c25c989ccc24f3ab42ec649617d3f21289" -dependencies = [ - "openzeppelin_access", - "openzeppelin_account", - "openzeppelin_finance", - "openzeppelin_introspection", - "openzeppelin_token", - "openzeppelin_upgrades", -] - -[[package]] -name = "openzeppelin_security" -version = "0.17.0" -source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.17.0#bf5d02c25c989ccc24f3ab42ec649617d3f21289" - -[[package]] -name = "openzeppelin_token" -version = "0.17.0" -source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.17.0#bf5d02c25c989ccc24f3ab42ec649617d3f21289" -dependencies = [ - "openzeppelin_account", - "openzeppelin_governance", - "openzeppelin_introspection", -] - -[[package]] -name = "openzeppelin_upgrades" -version = "0.17.0" -source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.17.0#bf5d02c25c989ccc24f3ab42ec649617d3f21289" - -[[package]] -name = "openzeppelin_utils" -version = "0.17.0" -source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.17.0#bf5d02c25c989ccc24f3ab42ec649617d3f21289" diff --git a/land_registry/Scarb.toml b/land_registry/Scarb.toml index 0dc3a489..9b84c580 100644 --- a/land_registry/Scarb.toml +++ b/land_registry/Scarb.toml @@ -1,9 +1,24 @@ [package] name = "landver" version = "0.1.0" -edition = "2024_07" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html -[dependencies] + +[workspace] +members = ["land_registry/*"] + +[workspace.package] +description = "Land Registry." +cairo-version = "2.8.2" +version = "0.1.0" +readme = "README.md" +repository = "https://github.com/NoshonNetworks/landver" +license-file = "LICENSE" + +[workspace.dependencies] +cairo_test = "2.8.0" openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.17.0" } +starknet = ">=2.8.0" + +[[target.starknet-contract]] diff --git a/land_registry/src/contracts/LandRegistry.cairo b/land_registry/src/contracts/LandRegistry.cairo index 4081b4ef..4f93dd23 100644 --- a/land_registry/src/contracts/LandRegistry.cairo +++ b/land_registry/src/contracts/LandRegistry.cairo @@ -1,10 +1,16 @@ -use core::starknet::ContractAddress; -use models::ModelLandRegistry; - #[starknet::contract] -pub mod LandRegistry { +mod LandRegistry { use super::ContractAddress; use super::ModelLandRegistry::{Land, Event}; + use super::ILandNFT; + + #[storage] + struct Storage { + lands: LegacyMap, + owner_lands: LegacyMap>, + owner_land_count: LegacyMap, + land_nft: ContractAddress, + } #[constructor] fn constructor(ref self: ContractState, land_nft: ContractAddress) { @@ -18,7 +24,8 @@ pub mod LandRegistry { location: felt252, area: u256, land_use: felt252, - ) -> LandDetails { + document_hash: felt252 + ) -> Land { let caller = get_caller_address(); let new_land = Land { owner: caller, @@ -35,23 +42,26 @@ pub mod LandRegistry { self.owner_lands.write((caller, count), land_id); self.owner_land_count.write(caller, count + 1); - self - .emit( - Event::LandRegistered( - LandRegistered { - land_id: land_id, - owner: caller, - location: location, - area: area, - land_use: land_use, - } - ) - ); + self.emit(Event::LandRegistered(LandRegistered { + land_id: land_id, + owner: caller, + location: location, + area: area, + land_use: land_use, + })); // Mint NFT ILandNFT::mint_land( - self.land_nft.read(), caller, land_id, location, area, land_use, document_hash + self.land_nft.read(), + caller, + land_id, + location, + area, + land_use, + document_hash ); + + new_land } #[external(v0)] @@ -71,17 +81,16 @@ pub mod LandRegistry { self.owner_land_count.write(new_owner, to_count + 1); self.owner_land_count.write(caller, from_count - 1); - self - .emit( - Event::LandTransferred( - LandTransferred { land_id: land_id, from_owner: caller, to_owner: new_owner, } - ) - ); + self.emit(Event::LandTransferred(LandTransferred { + land_id: land_id, + from_owner: caller, + to_owner: new_owner, + })); // Transfer NFT - ILandNFT::transferFrom(self.land_nft.read(), caller, new_owner, land_id); + ILandNFT::transfer_from(self.land_nft.read(), caller, new_owner, land_id); } - + #[external(v0)] fn get_land_details(self: @ContractState, land_id: u256) -> Land { self.lands.read(land_id) diff --git a/land_registry/src/traits/ILandNFT.cairo b/land_registry/src/traits/ILandNFT.cairo index 65f52afa..f6b3aa8b 100644 --- a/land_registry/src/traits/ILandNFT.cairo +++ b/land_registry/src/traits/ILandNFT.cairo @@ -1,13 +1,10 @@ use core::starknet::ContractAddress; -use openzeppelin::token::erc721::ERC721; -use models::ModelNFT; -use openzeppelin::introspection::src5::SRC5Component; -use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl}; +use super::ModelNFT::LandDetails; #[starknet::interface] -trait ILandNFT { +trait ILandNFT { fn mint_land( - ref self: ContractState, + ref self: TContractState, to: ContractAddress, token_id: u256, location: felt252, @@ -17,7 +14,7 @@ trait ILandNFT { ); fn update_land_details( - ref self: ContractState, + ref self: TContractState, token_id: u256, location: felt252, area: u256, @@ -26,6 +23,14 @@ trait ILandNFT { document_hash: felt252 ); - fn get_land_details(self: @ContractState, token_id: u256) -> LandDetails; -} + fn get_land_details(self: @TContractState, token_id: u256) -> LandDetails; + // ERC721 functions + fn balance_of(self: @TContractState, account: ContractAddress) -> u256; + fn owner_of(self: @TContractState, token_id: u256) -> ContractAddress; + fn transfer_from(ref self: TContractState, from: ContractAddress, to: ContractAddress, token_id: u256); + fn approve(ref self: TContractState, to: ContractAddress, token_id: u256); + fn get_approved(self: @TContractState, token_id: u256) -> ContractAddress; + fn set_approval_for_all(ref self: TContractState, operator: ContractAddress, approved: bool); + fn is_approved_for_all(self: @TContractState, owner: ContractAddress, operator: ContractAddress) -> bool; +} \ No newline at end of file From 16c489bd72c91b39bc1f1dab7695592ac2ef1b19 Mon Sep 17 00:00:00 2001 From: Fishon Amos Date: Tue, 8 Oct 2024 12:51:49 +0100 Subject: [PATCH 2/5] land registry --- land_registry/src/contracts/LandHolder.cairo | 6 +- .../src/contracts/LandInspector.cairo | 10 +- land_registry/src/contracts/LandNFT.cairo | 194 +++++++------- .../src/contracts/LandRegistry.cairo | 240 +++++++----------- .../src/contracts/LandVerification.cairo | 1 + land_registry/src/lib.cairo | 2 +- land_registry/src/models/model_nft.cairo | 3 +- land_registry/src/models/model_registry.cairo | 2 +- .../src/models/model_transaction.cairo | 4 +- .../src/models/model_verification.cairo | 1 - land_registry/src/traits/ILandHolder.cairo | 16 +- land_registry/src/traits/ILandNFT.cairo | 10 +- land_registry/src/traits/ILandRegistry.cairo | 5 +- .../src/traits/ILandTransaction.cairo | 12 +- 14 files changed, 253 insertions(+), 253 deletions(-) diff --git a/land_registry/src/contracts/LandHolder.cairo b/land_registry/src/contracts/LandHolder.cairo index bf64416d..bbc4b44a 100644 --- a/land_registry/src/contracts/LandHolder.cairo +++ b/land_registry/src/contracts/LandHolder.cairo @@ -5,12 +5,12 @@ mod LandHolder { #[storage] struct Storage { - lands: LegacyMap, - owner_lands: LegacyMap>, + lands: Map, + owner_lands: Map>, } #[constructor] - fn constructor(ref self: ContractState) {// Initialize any necessary state + fn constructor(ref self: ContractState) { // Initialize any necessary state } #[external(v0)] diff --git a/land_registry/src/contracts/LandInspector.cairo b/land_registry/src/contracts/LandInspector.cairo index 3fdce453..e6462964 100644 --- a/land_registry/src/contracts/LandInspector.cairo +++ b/land_registry/src/contracts/LandInspector.cairo @@ -2,14 +2,18 @@ mod LandInspector { use super::{ILandInspector, LandDetails, ContractAddress, ArrayTrait}; use core::starknet::get_caller_address; + use starknet::storage::{ + StoragePointerReadAccess, StoragePointerWriteAccess, StoragePathEntry, Map + }; + #[storage] struct Storage { land_registry: ContractAddress, - inspectors: LegacyMap, + inspectors: Map, pending_requests: Array, - land_details: LegacyMap, - request_status: LegacyMap, + land_details: Map, + request_status: Map, } #[constructor] diff --git a/land_registry/src/contracts/LandNFT.cairo b/land_registry/src/contracts/LandNFT.cairo index 6191adb7..548ba07a 100644 --- a/land_registry/src/contracts/LandNFT.cairo +++ b/land_registry/src/contracts/LandNFT.cairo @@ -1,103 +1,127 @@ -#[starknet::contract] -mod LandNFT { - use super::ContractAddress; - use super::ERC721; -use super::ModelNFT::{LandDetails, Event}; - use models::ModelNFT; - use openzeppelin::introspection::src5::SRC5Component; - use openzeppelin::token::erc721::{ERC721Component, ERC721HooksEmptyImpl}; - use starknet::ContractAddress; - - #[constructor] - fn constructor( - ref self: ContractState, name: felt252, symbol: felt252, land_registry: ContractAddress - ) { - self.erc721.initializer(name, symbol); - self.land_registry.write(land_registry); - } - - #[external(v0)] +#[starknet::interface] +trait ILandNFT { fn mint_land( - ref self: ContractState, + ref self: TContractState, to: ContractAddress, token_id: u256, location: felt252, area: u256, land_use: felt252, - ) { - assert(get_caller_address() == self.land_registry.read(), 'Only LandRegistry can mint'); - - self.erc721._mint(to, token_id); - - let land_details = LandDetails { - location: location, - area: area, - land_use: land_use, - is_verified: false, - document_hash: document_hash, - }; - self.land_details.write(token_id, land_details); - - self.emit(Event::LandMinted(LandMinted { token_id: token_id, owner: to })); - - - - let land_details = LandDetails { - - self - .emit( - Event::LandDetailsUpdated( - LandDetailsUpdated { - token_id: token_id, - location: location, - area: area, - land_use: land_use, - is_verified: false, - document_hash: document_hash, - } - ) - ); + document_hash: felt252 + ); + fn verify_land(ref self: TContractState, token_id: u256, verifier: ContractAddress); + fn get_land_details(self: @TContractState, token_id: u256) -> LandDetails; + fn get_owner_lands(self: @TContractState, owner: ContractAddress) -> Array; +} + +#[starknet::contract] +mod LandNFT { + use starknet::ContractAddress; + use openzeppelin::token::erc721::ERC721; + use openzeppelin::access::ownable::OwnableComponent; + + #[storage] + struct Storage { + land_registry: ContractAddress, + land_details: LegacyMap, + owner_lands: LegacyMap>, } - #[external(v0)] - fn update_land_details( - ref self: ContractState, - token_id: u256, + #[derive(Drop, Serde, starknet::Store)] + struct LandDetails { location: felt252, area: u256, land_use: felt252, is_verified: bool, - document_hash: felt252 + document_hash: felt252, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + LandMinted: LandMinted, + LandVerified: LandVerified, + } + + #[derive(Drop, starknet::Event)] + struct LandMinted { + token_id: u256, + owner: ContractAddress, + } + + #[derive(Drop, starknet::Event)] + struct LandVerified { + token_id: u256, + verifier: ContractAddress, + } + + #[constructor] + fn constructor( + ref self: ContractState, + name: felt252, + symbol: felt252, + land_registry: ContractAddress ) { - assert(get_caller_address() == self.land_registry.read(), 'Only LandRegistry can update'); - - let land_details = LandDetails { - location: location, - area: area, - land_use: land_use, - is_verified: is_verified, - document_hash: document_hash, - }; - self.land_details.write(token_id, land_details); - - self - .emit( - Event::LandDetailsUpdated( - LandDetailsUpdated { - token_id: token_id, - location: location, - area: area, - land_use: land_use, - is_verified: is_verified, - document_hash: document_hash, - } - ) - ); + self.initializer(name, symbol); + self.land_registry.write(land_registry); + self._transfer_ownership(land_registry); } #[external(v0)] - fn get_land_details(self: @ContractState, token_id: u256) -> LandDetails { - self.land_details.read(token_id) + impl LandNFTImpl of ILandNFT { + fn mint_land( + ref self: ContractState, + to: ContractAddress, + token_id: u256, + location: felt252, + area: u256, + land_use: felt252, + document_hash: felt252 + ) { + self.assert_only_owner(); + + self._mint(to, token_id); + + let land_details = LandDetails { + location, + area, + land_use, + is_verified: false, + document_hash, + }; + self.land_details.write(token_id, land_details); + + let mut owner_lands = self.owner_lands.read(to); + owner_lands.append(token_id); + self.owner_lands.write(to, owner_lands); + + self.emit(LandMinted { token_id, owner: to }); + } + + fn verify_land(ref self: ContractState, token_id: u256, verifier: ContractAddress) { + self.assert_only_owner(); + + let mut land_details = self.land_details.read(token_id); + land_details.is_verified = true; + self.land_details.write(token_id, land_details); + + self.emit(LandVerified { token_id, verifier }); + } + + fn get_land_details(self: @ContractState, token_id: u256) -> LandDetails { + self.land_details.read(token_id) + } + + fn get_owner_lands(self: @ContractState, owner: ContractAddress) -> Array { + self.owner_lands.read(owner) + } + } + + #[generate_trait] + impl PrivateMethods of PrivateMethodsTrait { + fn assert_only_owner(self: @ContractState) { + let caller = starknet::get_caller_address(); + assert(caller == self.land_registry.read(), 'Only LandRegistry can call'); + } } - // Implement } diff --git a/land_registry/src/contracts/LandRegistry.cairo b/land_registry/src/contracts/LandRegistry.cairo index 4f93dd23..235889d7 100644 --- a/land_registry/src/contracts/LandRegistry.cairo +++ b/land_registry/src/contracts/LandRegistry.cairo @@ -1,174 +1,126 @@ +use starknet::ContractAddress; + +#[starknet::interface] +trait ILandRegistry { + fn register_land( + ref self: TContractState, + owner: ContractAddress, + location: felt252, + area: u256, + land_use: felt252, + document_hash: felt252 + ) -> u256; + fn transfer_land(ref self: TContractState, land_id: u256, new_owner: ContractAddress); + fn verify_land(ref self: TContractState, land_id: u256, verifier: ContractAddress); + fn get_land_details(self: @TContractState, land_id: u256) -> Land; + fn get_owner_lands(self: @TContractState, owner: ContractAddress) -> Array; +} + +#[derive(Drop, Serde, starknet::Store)] +struct Land { + owner: ContractAddress, + location: felt252, + area: u256, + land_use: felt252, + is_verified: bool, + last_transaction_timestamp: u64, + document_hash: felt252, +} + #[starknet::contract] mod LandRegistry { - use super::ContractAddress; - use super::ModelLandRegistry::{Land, Event}; - use super::ILandNFT; + use super::{ILandRegistry, Land, ContractAddress}; + use starknet::{get_caller_address, get_block_timestamp}; + use land_registry::contracts::LandNFT::{ILandNFTDispatcher, ILandNFTDispatcherTrait}; #[storage] struct Storage { - lands: LegacyMap, - owner_lands: LegacyMap>, - owner_land_count: LegacyMap, - land_nft: ContractAddress, + land_nft: ILandNFTDispatcher, + verifiers: LegacyMap, + next_land_id: u256, } - #[constructor] - fn constructor(ref self: ContractState, land_nft: ContractAddress) { - self.land_nft.write(land_nft); + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + LandRegistered: LandRegistered, + LandTransferred: LandTransferred, + LandVerified: LandVerified, } - #[external(v0)] - fn register_land( - ref self: ContractState, + #[derive(Drop, starknet::Event)] + struct LandRegistered { land_id: u256, + owner: ContractAddress, location: felt252, area: u256, land_use: felt252, - document_hash: felt252 - ) -> Land { - let caller = get_caller_address(); - let new_land = Land { - owner: caller, - location: location, - area: area, - land_use: land_use, - is_registered: true, - is_verified: false, - last_transaction_timestamp: get_block_timestamp(), - }; - self.lands.write(land_id, new_land); - - let count = self.owner_land_count.read(caller); - self.owner_lands.write((caller, count), land_id); - self.owner_land_count.write(caller, count + 1); - - self.emit(Event::LandRegistered(LandRegistered { - land_id: land_id, - owner: caller, - location: location, - area: area, - land_use: land_use, - })); - - // Mint NFT - ILandNFT::mint_land( - self.land_nft.read(), - caller, - land_id, - location, - area, - land_use, - document_hash - ); - - new_land - } - - #[external(v0)] - fn transfer_land(ref self: ContractState, land_id: u256, new_owner: ContractAddress) { - let caller = get_caller_address(); - let mut land = self.lands.read(land_id); - assert(land.owner == caller, 'Only the current owner can transfer the land'); - assert(land.is_registered, 'Land is not registered'); - land.owner = new_owner; - land.last_transaction_timestamp = get_block_timestamp(); - self.lands.write(land_id, land); - - // Update owner_lands and owner_land_count - let from_count = self.owner_land_count.read(caller); - let to_count = self.owner_land_count.read(new_owner); - self.owner_lands.write((new_owner, to_count), land_id); - self.owner_land_count.write(new_owner, to_count + 1); - self.owner_land_count.write(caller, from_count - 1); - - self.emit(Event::LandTransferred(LandTransferred { - land_id: land_id, - from_owner: caller, - to_owner: new_owner, - })); - - // Transfer NFT - ILandNFT::transfer_from(self.land_nft.read(), caller, new_owner, land_id); - } - - #[external(v0)] - fn get_land_details(self: @ContractState, land_id: u256) -> Land { - self.lands.read(land_id) } - #[external(v0)] - fn get_owner_lands(self: @ContractState, owner: ContractAddress) -> Vec { - let mut lands = Vec::new(); - let count = self.owner_land_count.read(owner); - for i in 0..count { - let land_id = self.owner_lands.read((owner, i)); - lands.push(land_id); - } - lands + #[derive(Drop, starknet::Event)] + struct LandTransferred { + land_id: u256, + from_owner: ContractAddress, + to_owner: ContractAddress, } - #[external(v0)] - fn get_land_count(self: @ContractState) -> u256 { - self.owner_land_count.read(get_caller_address()) + #[derive(Drop, starknet::Event)] + struct LandVerified { + land_id: u256, + verifier: ContractAddress, } - #[external(v0)] - fn get_land_count_for_owner(self: @ContractState, owner: ContractAddress) -> u256 { - self.owner_land_count.read(owner) + #[constructor] + fn constructor(ref self: ContractState, initial_verifier: ContractAddress, land_nft_address: ContractAddress) { + self.verifiers.write(initial_verifier, true); + self.land_nft.write(ILandNFTDispatcher { contract_address: land_nft_address }); + self.next_land_id.write(1); } #[external(v0)] - fn get_land_owner(self: @ContractState, land_id: u256) -> ContractAddress { - self.lands.read(land_id).owner - } + impl LandRegistryImpl of ILandRegistry { + fn register_land( + ref self: ContractState, + owner: ContractAddress, + location: felt252, + area: u256, + land_use: felt252, + document_hash: felt252 + ) -> u256 { + let land_id = self.next_land_id.read(); + self.next_land_id.write(land_id + 1); + + self.land_nft.read().mint_land(owner, land_id, location, area, land_use, document_hash); + + self.emit(LandRegistered { land_id, owner, location, area, land_use }); + + land_id + } - #[external(v0)] - fn get_land_location(self: @ContractState, land_id: u256) -> felt252 { - self.lands.read(land_id).location - } + fn transfer_land(ref self: ContractState, land_id: u256, new_owner: ContractAddress) { + let caller = get_caller_address(); + let current_owner = self.land_nft.read().owner_of(land_id); + assert(current_owner == caller, 'Only the current owner can transfer'); - #[external(v0)] - fn get_land_area(self: @ContractState, land_id: u256) -> u256 { - self.lands.read(land_id).area - } + self.land_nft.read().transfer_from(caller, new_owner, land_id); - #[external(v0)] - fn get_land_land_use(self: @ContractState, land_id: u256) -> felt252 { - self.lands.read(land_id).land_use - } + self.emit(LandTransferred { land_id, from_owner: caller, to_owner: new_owner }); + } - #[external(v0)] - fn get_land_is_registered(self: @ContractState, land_id: u256) -> bool { - self.lands.read(land_id).is_registered - } + fn verify_land(ref self: ContractState, land_id: u256, verifier: ContractAddress) { + assert(self.verifiers.read(verifier), 'Not an authorized verifier'); + + self.land_nft.read().verify_land(land_id, verifier); - #[external(v0)] - fn get_land_is_verified(self: @ContractState, land_id: u256) -> bool { - self.lands.read(land_id).is_verified - } + self.emit(LandVerified { land_id, verifier }); + } - #[external(v0)] - fn get_land_document_hash(self: @ContractState, land_id: u256) -> felt252 { - self.lands.read(land_id).document_hash - } + fn get_land_details(self: @ContractState, land_id: u256) -> Land { + self.land_nft.read().get_land_details(land_id) + } - #[external(v0)] - fn get_land_last_transaction_timestamp(self: @ContractState, land_id: u256) -> u64 { - self.lands.read(land_id).last_transaction_timestamp + fn get_owner_lands(self: @ContractState, owner: ContractAddress) -> Array { + self.land_nft.read().get_owner_lands(owner) + } } -} -// #[starknet::interface] -// trait ILandNFT { -// fn mint_land( -// ref self: ContractState, -// to: ContractAddress, -// token_id: u256, -// location: felt252, -// area: u256, -// land_use: felt252, -// document_hash: felt252 -// ); -// fn transferFrom(ref self: ContractState, from: ContractAddress, to: ContractAddress, -// token_id: u256); -// } - +} \ No newline at end of file diff --git a/land_registry/src/contracts/LandVerification.cairo b/land_registry/src/contracts/LandVerification.cairo index 611fef86..aa900d9b 100644 --- a/land_registry/src/contracts/LandVerification.cairo +++ b/land_registry/src/contracts/LandVerification.cairo @@ -4,6 +4,7 @@ mod LandVerification { use core::starknet::ContractAddress; use super::LandRegistry; use super::ILandRegistry; + use super::ILandTransaction; #[constructor] fn constructor(ref self: ContractState, land_registry: ContractAddress) { diff --git a/land_registry/src/lib.cairo b/land_registry/src/lib.cairo index da6528f8..af765372 100644 --- a/land_registry/src/lib.cairo +++ b/land_registry/src/lib.cairo @@ -9,4 +9,4 @@ mod models { mod model_nft; mod model_registry; mod model_transaction; -} \ No newline at end of file +} diff --git a/land_registry/src/models/model_nft.cairo b/land_registry/src/models/model_nft.cairo index 054293b0..ce8d40c3 100644 --- a/land_registry/src/models/model_nft.cairo +++ b/land_registry/src/models/model_nft.cairo @@ -10,7 +10,7 @@ mod ModelNFT { struct Storage { #[substorage(v0)] erc721: ERC721::Storage, - land_details: LegacyMap, + land_details: Map, land_registry: ContractAddress, } @@ -23,7 +23,6 @@ mod ModelNFT { document_hash: felt252, } - #[derive(Drop, starknet::Event)] struct LandMinted { diff --git a/land_registry/src/models/model_registry.cairo b/land_registry/src/models/model_registry.cairo index b6a7c51e..fdb8bcac 100644 --- a/land_registry/src/models/model_registry.cairo +++ b/land_registry/src/models/model_registry.cairo @@ -46,7 +46,7 @@ mod ModelLandRegistry { #[storage] struct Storage { lands: LegacyMap, - owner_lands: LegacyMap>, + owner_lands: LMap>, owner_land_count: LegacyMap, land_nft: ContractAddress, } diff --git a/land_registry/src/models/model_transaction.cairo b/land_registry/src/models/model_transaction.cairo index c8b314be..a331a712 100644 --- a/land_registry/src/models/model_transaction.cairo +++ b/land_registry/src/models/model_transaction.cairo @@ -2,7 +2,7 @@ mod ModelLandTransaction { use core::starknet::get_caller_address; use core::starknet::ContractAddress; use super::LandRegistry; - + #[event] #[derive(Drop, starknet::Event)] enum Event { @@ -31,7 +31,7 @@ mod ModelLandTransaction { #[storage] struct Storage { - transactions: LegacyMap, + transactions: Map, transaction_count: u256, land_registry: ContractAddress, } diff --git a/land_registry/src/models/model_verification.cairo b/land_registry/src/models/model_verification.cairo index ba59a6bd..a965baff 100644 --- a/land_registry/src/models/model_verification.cairo +++ b/land_registry/src/models/model_verification.cairo @@ -1,4 +1,3 @@ - mod ModelVerification { #[storage] struct Storage { diff --git a/land_registry/src/traits/ILandHolder.cairo b/land_registry/src/traits/ILandHolder.cairo index fd86dd12..f7fbf27f 100644 --- a/land_registry/src/traits/ILandHolder.cairo +++ b/land_registry/src/traits/ILandHolder.cairo @@ -1,6 +1,6 @@ use core::starknet::ContractAddress; #[starknet::interface] -pub trait ILandHolder { +pub trait ILandHolder { fn get_registered_land( self: @TContractState, land_id: u256, contract_address: ContractAddress ) -> Option; @@ -10,7 +10,13 @@ pub trait ILandHolder { self: @TContractState, owner_address: Address ) -> Array; - fn check_land_ownership(self: @TContractState, land_id: u256, contract_address: ContractAddress) -> bool; - fn update_land_document(ref self: TContractState, land_id: u256, contract_address: ContractAddress); - fn remove_registered_land(ref self: TContractState, land_id: u256, contract_address: ContractAddress); -} \ No newline at end of file + fn check_land_ownership( + self: @TContractState, land_id: u256, contract_address: ContractAddress + ) -> bool; + fn update_land_document( + ref self: TContractState, land_id: u256, contract_address: ContractAddress + ); + fn remove_registered_land( + ref self: TContractState, land_id: u256, contract_address: ContractAddress + ); +} diff --git a/land_registry/src/traits/ILandNFT.cairo b/land_registry/src/traits/ILandNFT.cairo index f6b3aa8b..4b77e879 100644 --- a/land_registry/src/traits/ILandNFT.cairo +++ b/land_registry/src/traits/ILandNFT.cairo @@ -28,9 +28,13 @@ trait ILandNFT { // ERC721 functions fn balance_of(self: @TContractState, account: ContractAddress) -> u256; fn owner_of(self: @TContractState, token_id: u256) -> ContractAddress; - fn transfer_from(ref self: TContractState, from: ContractAddress, to: ContractAddress, token_id: u256); + fn transfer_from( + ref self: TContractState, from: ContractAddress, to: ContractAddress, token_id: u256 + ); fn approve(ref self: TContractState, to: ContractAddress, token_id: u256); fn get_approved(self: @TContractState, token_id: u256) -> ContractAddress; fn set_approval_for_all(ref self: TContractState, operator: ContractAddress, approved: bool); - fn is_approved_for_all(self: @TContractState, owner: ContractAddress, operator: ContractAddress) -> bool; -} \ No newline at end of file + fn is_approved_for_all( + self: @TContractState, owner: ContractAddress, operator: ContractAddress + ) -> bool; +} diff --git a/land_registry/src/traits/ILandRegistry.cairo b/land_registry/src/traits/ILandRegistry.cairo index 49eaead5..8318ffa4 100644 --- a/land_registry/src/traits/ILandRegistry.cairo +++ b/land_registry/src/traits/ILandRegistry.cairo @@ -2,6 +2,7 @@ use core::starknet::ContractAddress; #[starknet::interface] trait ILandRegistry { fn verify_land(self: @TContractState, land_id: u256, verifier: ContractAddress); - fn register_land(ref self: TContractState, land_id: u256, owner: ContractAddress) -> LandDetails; - + fn register_land( + ref self: TContractState, land_id: u256, owner: ContractAddress + ) -> LandDetails; } diff --git a/land_registry/src/traits/ILandTransaction.cairo b/land_registry/src/traits/ILandTransaction.cairo index e4d09d75..371a5dff 100644 --- a/land_registry/src/traits/ILandTransaction.cairo +++ b/land_registry/src/traits/ILandTransaction.cairo @@ -1,10 +1,20 @@ use core::starknet::ContractAddress; #[starknet::interface] -trait ILandInspector { +pub trait ILandInspector { fn recive_land_request(ref self: ContractState, land_id: u256); fn view_land(self: @ContractState, land_id: u256); fn approve_land_request(ref self: ContractState, land_id: u256); fn reject_land_request(ref self: ContractState, land_id: u256); fn delete_land_request(ref self: ContractState, land_id: u256); } + +#[starknet::interface] +pub trait ILandTransaction { + fn create_transaction(ref self: ContractState, land_id: u256, from_owner: ContractAddress, to_owner: ContractAddress, transaction_type: u8) -> u256; + fn get_transaction(self: @ContractState, transaction_id: u256); + fn get_all_transactions(self: @ContractState); + fn get_transactions_by_land_id(self: @ContractState, land_id: u256); + fn get_transactions_by_owner(self: @ContractState, owner: ContractAddress); + fn get_transactions_by_type(self: @ContractState, transaction_type: u8); +} From b4a120363025c1fc3f000d4936113ccf591ab388 Mon Sep 17 00:00:00 2001 From: Fishon Amos Date: Tue, 8 Oct 2024 14:05:26 +0100 Subject: [PATCH 3/5] land registry --- .DS_Store | Bin 6148 -> 6148 bytes land_registry/Scarb.lock | 107 +++++++++++++++- land_registry/Scarb.toml | 20 +-- land_registry/src/contracts/LandHolder.cairo | 91 -------------- .../src/contracts/LandInspector.cairo | 72 ----------- land_registry/src/contracts/LandNFT.cairo | 16 ++- .../src/contracts/LandRegistry.cairo | 4 +- .../src/contracts/LandTransaction.cairo | 119 ------------------ .../src/contracts/LandVerification.cairo | 29 ----- land_registry/src/lib.cairo | 17 +-- land_registry/src/models/model_nft.cairo | 43 ------- land_registry/src/models/model_registry.cairo | 61 --------- .../src/models/model_transaction.cairo | 38 ------ .../src/models/model_verification.cairo | 7 -- .../src/tests/test_land_registry.cairo | 110 ++++++++++++++++ land_registry/src/traits/ILandHolder.cairo | 22 ---- land_registry/src/traits/ILandInspector.cairo | 13 -- land_registry/src/traits/ILandNFT.cairo | 40 ------ land_registry/src/traits/ILandRegistry.cairo | 8 -- .../src/traits/ILandTransaction.cairo | 20 --- .../src/traits/ILandVerification.cairo | 22 ---- 21 files changed, 246 insertions(+), 613 deletions(-) delete mode 100644 land_registry/src/contracts/LandHolder.cairo delete mode 100644 land_registry/src/contracts/LandInspector.cairo delete mode 100644 land_registry/src/contracts/LandTransaction.cairo delete mode 100644 land_registry/src/contracts/LandVerification.cairo delete mode 100644 land_registry/src/models/model_nft.cairo delete mode 100644 land_registry/src/models/model_registry.cairo delete mode 100644 land_registry/src/models/model_transaction.cairo delete mode 100644 land_registry/src/models/model_verification.cairo create mode 100644 land_registry/src/tests/test_land_registry.cairo delete mode 100644 land_registry/src/traits/ILandHolder.cairo delete mode 100644 land_registry/src/traits/ILandInspector.cairo delete mode 100644 land_registry/src/traits/ILandNFT.cairo delete mode 100644 land_registry/src/traits/ILandRegistry.cairo delete mode 100644 land_registry/src/traits/ILandTransaction.cairo delete mode 100644 land_registry/src/traits/ILandVerification.cairo diff --git a/.DS_Store b/.DS_Store index c6dc4e16763c8ac8a77afcc953447f8f88afb497..38922d8e957f8ef8aa4ee0239b8966f8207b691c 100644 GIT binary patch delta 39 vcmZoMXfc@J&&azmU^g=(?_?ep|H-{9T9eIL`8SKPeq@^1(6pJI<1aq|?#m2g delta 156 zcmZoMXfc@J&nU1lU^g?Pz+@g4e|=7dWQKf(Jcbg6B8EgDyM&?GGbcYeDJMUPfq_8) zh}Q$L-hVJ)V3-`iqU)W?Pytk%%TU0O!;p%up0OKQJ&?@-RD+_vEVw8yCqFM8D95, - owner_lands: Map>, - } - - #[constructor] - fn constructor(ref self: ContractState) { // Initialize any necessary state - } - - #[external(v0)] - impl LandHolderImpl of ILandHolder { - fn get_registered_land( - self: @ContractState, land_id: u256, document_hash: felt252 - ) -> Option { - let land = self.lands.read(land_id); - if land.document_hash == document_hash { - Option::Some(land) - } else { - Option::None - } - } - - fn get_all_registered_lands( - self: @ContractState, owner: ContractAddress - ) -> Array { - let mut result = ArrayTrait::new(); - let land_ids = self.owner_lands.read(owner); - let mut i = 0; - loop { - if i >= land_ids.len() { - break; - } - let land_id = *land_ids.at(i); - let land = self.lands.read(land_id); - result.append(land); - i += 1; - }; - result - } - - fn check_land_ownership( - self: @ContractState, land_id: u256, owner: ContractAddress - ) -> bool { - let land = self.lands.read(land_id); - land.owner == owner - } - - fn update_land_document( - ref self: ContractState, land_id: u256, new_document_hash: felt252 - ) { - let mut land = self.lands.read(land_id); - assert(land.owner == get_caller_address(), 'Only owner can update'); - land.document_hash = new_document_hash; - self.lands.write(land_id, land); - } - - fn remove_registered_land(ref self: ContractState, land_id: u256) { - let land = self.lands.read(land_id); - assert(land.owner == get_caller_address(), 'Only owner can remove'); - - // Remove from lands mapping - self - .lands - .write( - land_id, - LandRegistered { land_id: 0, owner: ContractAddress::from(0), document_hash: 0 } - ); - - // Remove from owner_lands array - let mut owner_lands = self.owner_lands.read(land.owner); - let mut i = 0; - loop { - if i >= owner_lands.len() { - break; - } - if *owner_lands.at(i) == land_id { - owner_lands.pop_front(); - break; - } - i += 1; - }; - self.owner_lands.write(land.owner, owner_lands); - } - } -} diff --git a/land_registry/src/contracts/LandInspector.cairo b/land_registry/src/contracts/LandInspector.cairo deleted file mode 100644 index e6462964..00000000 --- a/land_registry/src/contracts/LandInspector.cairo +++ /dev/null @@ -1,72 +0,0 @@ -#[starknet::contract] -mod LandInspector { - use super::{ILandInspector, LandDetails, ContractAddress, ArrayTrait}; - use core::starknet::get_caller_address; - use starknet::storage::{ - StoragePointerReadAccess, StoragePointerWriteAccess, StoragePathEntry, Map - }; - - - #[storage] - struct Storage { - land_registry: ContractAddress, - inspectors: Map, - pending_requests: Array, - land_details: Map, - request_status: Map, - } - - #[constructor] - fn constructor( - ref self: ContractState, land_registry: ContractAddress, initial_inspector: ContractAddress - ) { - self.land_registry.write(land_registry); - self.inspectors.write(initial_inspector, true); - } - - #[external(v0)] - impl LandInspectorImpl of super::ILandInspector { - fn receive_land_request(ref self: ContractState, land_id: u256) { - // Only land registry can submit requests - assert(get_caller_address() == self.land_registry.read(), 'Unauthorized'); - self.pending_requests.write(self.pending_requests.read() + 1); - self.request_status.write(land_id, 'pending'); - } - - fn view_land(self: @ContractState, land_id: u256) -> LandDetails { - assert(self.inspectors.read(get_caller_address()), 'Not an inspector'); - self.land_details.read(land_id) - } - - fn approve_land_request(ref self: ContractState, land_id: u256) { - assert(self.inspectors.read(get_caller_address()), 'Not an inspector'); - assert(self.request_status.read(land_id) == 'pending', 'Not pending'); - self.request_status.write(land_id, 'approved'); - self._remove_from_pending(land_id); - // TODO: Notify land registry of approval - } - - fn reject_land_request(ref self: ContractState, land_id: u256, reason: felt252) { - assert(self.inspectors.read(get_caller_address()), 'Not an inspector'); - assert(self.request_status.read(land_id) == 'pending', 'Not pending'); - self.request_status.write(land_id, 'rejected'); - // TODO: Store rejection reason - self._remove_from_pending(land_id); - // TODO: Notify land registry of rejection - } - - fn delete_land_request(ref self: ContractState, land_id: u256) { - assert(get_caller_address() == self.land_registry.read(), 'Unauthorized'); - self.request_status.write(land_id, 'deleted'); - self._remove_from_pending(land_id); - } - - fn get_pending_requests(self: @ContractState) -> Array { - self.pending_requests.read() - } - - fn is_inspector(self: @ContractState, address: ContractAddress) -> bool { - self.inspectors.read(address) - } - } -} diff --git a/land_registry/src/contracts/LandNFT.cairo b/land_registry/src/contracts/LandNFT.cairo index 548ba07a..ac5c1715 100644 --- a/land_registry/src/contracts/LandNFT.cairo +++ b/land_registry/src/contracts/LandNFT.cairo @@ -1,5 +1,9 @@ +use core::starknet::ContractAddress; +use super land_registry::LandDetails; + #[starknet::interface] -trait ILandNFT { + +pub trait ILandNFT { fn mint_land( ref self: TContractState, to: ContractAddress, @@ -15,20 +19,21 @@ trait ILandNFT { } #[starknet::contract] -mod LandNFT { +pub mod LandNFT { use starknet::ContractAddress; use openzeppelin::token::erc721::ERC721; use openzeppelin::access::ownable::OwnableComponent; + use starknet::storage::Map; #[storage] struct Storage { land_registry: ContractAddress, - land_details: LegacyMap, - owner_lands: LegacyMap>, + land_details: Map, + owner_lands: Map>, } #[derive(Drop, Serde, starknet::Store)] - struct LandDetails { + pub struct LandDetails { location: felt252, area: u256, land_use: felt252, @@ -68,6 +73,7 @@ mod LandNFT { } #[external(v0)] + impl LandNFTImpl of ILandNFT { fn mint_land( ref self: ContractState, diff --git a/land_registry/src/contracts/LandRegistry.cairo b/land_registry/src/contracts/LandRegistry.cairo index 235889d7..134274bb 100644 --- a/land_registry/src/contracts/LandRegistry.cairo +++ b/land_registry/src/contracts/LandRegistry.cairo @@ -32,11 +32,12 @@ mod LandRegistry { use super::{ILandRegistry, Land, ContractAddress}; use starknet::{get_caller_address, get_block_timestamp}; use land_registry::contracts::LandNFT::{ILandNFTDispatcher, ILandNFTDispatcherTrait}; + use starknet::storage::Map; #[storage] struct Storage { land_nft: ILandNFTDispatcher, - verifiers: LegacyMap, + verifiers: Map, next_land_id: u256, } @@ -78,6 +79,7 @@ mod LandRegistry { } #[external(v0)] + #abi_embedV0 impl LandRegistryImpl of ILandRegistry { fn register_land( ref self: ContractState, diff --git a/land_registry/src/contracts/LandTransaction.cairo b/land_registry/src/contracts/LandTransaction.cairo deleted file mode 100644 index 170ff6b3..00000000 --- a/land_registry/src/contracts/LandTransaction.cairo +++ /dev/null @@ -1,119 +0,0 @@ -use core::starknet::ContractAddress; -use models::ModelLandTransaction; - -#[starknet::contract] -mod LandTransaction { - #[constructor] - fn constructor(ref self: ContractState, land_registry: ContractAddress) { - self.land_registry.write(land_registry); - } - - #[external(v0)] - fn create_transaction( - ref self: ContractState, - land_id: u256, - from_owner: ContractAddress, - to_owner: ContractAddress, - transaction_type: u8 - ) -> u256 { - assert( - get_caller_address() == self.land_registry.read(), - 'Only LandRegistry can create transactions' - ); - - let transaction_id = self.transaction_count.read() + 1; - self.transaction_count.write(transaction_id); - - let transaction = Transaction { - land_id: land_id, - from_owner: from_owner, - to_owner: to_owner, - transaction_type: transaction_type, - status: 0, // 0 for pending - initiation_date: get_block_timestamp(), - completion_date: 0, - }; - self.transactions.write(transaction_id, transaction); - - self - .emit( - Event::TransactionCreated( - TransactionCreated { - transaction_id: transaction_id, - land_id: land_id, - from_owner: from_owner, - to_owner: to_owner, - transaction_type: transaction_type, - } - ) - ); - - transaction_id - } - - #[external(v0)] - fn approve_transaction(ref self: ContractState, transaction_id: u256) { - let caller = get_caller_address(); - let mut transaction = self.transactions.read(transaction_id); - assert(transaction.to_owner == caller, 'Caller is not the transaction owner'); - assert(transaction.status == 0, 'Transaction is not pending'); - transaction.status = 1; // 1 for approved - transaction.completion_date = get_block_timestamp(); - self.transactions.write(transaction_id, transaction); - - // Call LandRegistry to transfer the land - ILandRegistry::transfer_land( - self.land_registry.read(), transaction.land_id, transaction.to_owner - ); - } - - #[external(v0)] - fn reject_transaction(self: @ContractState, transaction_id: u256) { - let caller = get_caller_address(); - let transaction = self.transactions.read(transaction_id); - assert(transaction.from_owner == caller, 'Caller is not the transaction owner'); - assert(transaction.status == 0, 'Transaction is not pending'); - transaction.status = 2; // 2 for rejected - self.transactions.write(transaction_id, transaction); - } - - #[external(v0)] - fn get_transaction_details(self: @ContractState, transaction_id: u256) -> Transaction { - return self.transactions.read(transaction_id); - } - - #[external(v0)] - fn get_transaction_status(self: @ContractState, transaction_id: u256) -> u8 { - return self.transactions.read(transaction_id).status; - } - - #[external(v0)] - fn get_transaction_initiation_date(self: @ContractState, transaction_id: u256) -> u64 { - return self.transactions.read(transaction_id).initiation_date; - } - - #[external(v0)] - fn get_transaction_completion_date(self: @ContractState, transaction_id: u256) -> u64 { - return self.transactions.read(transaction_id).completion_date; - } - - #[external(v0)] - fn get_transaction_type(self: @ContractState, transaction_id: u256) -> u8 { - return self.transactions.read(transaction_id).transaction_type; - } - - #[external(v0)] - fn get_transaction_from_owner(self: @ContractState, transaction_id: u256) -> ContractAddress { - return self.transactions.read(transaction_id).from_owner; - } - - #[external(v0)] - fn get_transaction_to_owner(self: @ContractState, transaction_id: u256) -> ContractAddress { - return self.transactions.read(transaction_id).to_owner; - } -} - -#[starknet::interface] -trait ILandRegistry { - fn transfer_land(ref self: ContractState, land_id: u256, new_owner: ContractAddress); -} diff --git a/land_registry/src/contracts/LandVerification.cairo b/land_registry/src/contracts/LandVerification.cairo deleted file mode 100644 index aa900d9b..00000000 --- a/land_registry/src/contracts/LandVerification.cairo +++ /dev/null @@ -1,29 +0,0 @@ -#[starknet::contract] -mod LandVerification { - use core::starknet::get_caller_address; - use core::starknet::ContractAddress; - use super::LandRegistry; - use super::ILandRegistry; - use super::ILandTransaction; - - #[constructor] - fn constructor(ref self: ContractState, land_registry: ContractAddress) { - self.land_registry.write(land_registry); - } - - #[external(v0)] - fn add_verifier(ref self: ContractState, verifier: ContractAddress) { - // Only contract owner should be able to add verifiers - self.verifiers.write(verifier, true); - } - - #[external(v0)] - fn verify_land(ref self: ContractState, land_id: u256) { - let caller = get_caller_address(); - assert(self.verifiers.read(caller), 'Caller is not an authorized verifier'); - - ILandRegistry::verify_land(self.land_registry.read(), land_id, caller); - } - // Implement (reject_land_verification, get_land_verification_status, etc.) -} - diff --git a/land_registry/src/lib.cairo b/land_registry/src/lib.cairo index af765372..a3a1654d 100644 --- a/land_registry/src/lib.cairo +++ b/land_registry/src/lib.cairo @@ -1,12 +1,15 @@ mod contracts { - mod LandNFT; mod LandRegistry; - mod LandTransaction; - mod LandVerification; + mod LandNFT; } -mod models { - mod model_nft; - mod model_registry; - mod model_transaction; +mod tests { + mod test_land_registry; } + +use contracts::LandRegistry::{LandRegistry, ILandRegistry, ILandRegistryDispatcher, ILandRegistryDispatcherTrait}; +use contracts::LandNFT::{LandNFT, ILandNFT, ILandNFTDispatcher, ILandNFTDispatcherTrait}; + +use contracts::LandRegistry::Land; +use contracts::LandNFT::LandDetails; + diff --git a/land_registry/src/models/model_nft.cairo b/land_registry/src/models/model_nft.cairo deleted file mode 100644 index ce8d40c3..00000000 --- a/land_registry/src/models/model_nft.cairo +++ /dev/null @@ -1,43 +0,0 @@ -mod ModelNFT { - use openzeppelin::token::erc721::ERC721; - use openzeppelin::utils::legacy_map::LegacyMap; - use openzeppelin::utils::contract_address::ContractAddress; - use openzeppelin::utils::felt252::felt252; - use openzeppelin::utils::u256::u256; - use core::starknet::ContractAddress; - - #[storage] - struct Storage { - #[substorage(v0)] - erc721: ERC721::Storage, - land_details: Map, - land_registry: ContractAddress, - } - - #[derive(Copy, Drop, Serde, starknet::Store)] - struct LandDetails { - location: felt252, - area: u256, - land_use: felt252, - is_verified: bool, - document_hash: felt252, - } - - - #[derive(Drop, starknet::Event)] - struct LandMinted { - token_id: u256, - owner: ContractAddress, - } - - #[derive(Drop, starknet::Event)] - struct LandDetailsUpdated { - token_id: u256, - location: felt252, - area: u256, - land_use: felt252, - is_verified: bool, - document_hash: felt252, - } -} - diff --git a/land_registry/src/models/model_registry.cairo b/land_registry/src/models/model_registry.cairo deleted file mode 100644 index fdb8bcac..00000000 --- a/land_registry/src/models/model_registry.cairo +++ /dev/null @@ -1,61 +0,0 @@ -mod ModelLandRegistry { - use core::starknet::get_caller_address; - use core::starknet::ContractAddress; - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - LandRegistered: LandRegistered, - LandTransferred: LandTransferred, - LandVerified: LandVerified, - } - - #[derive(Drop, starknet::Event)] - struct LandRegistered { - land_id: u256, - owner: ContractAddress, - location: felt252, - area: u256, - land_use: felt252, - } - - #[derive(Drop, starknet::Event)] - struct LandTransferred { - land_id: u256, - from_owner: ContractAddress, - to_owner: ContractAddress, - } - - #[derive(Drop, starknet::Event)] - struct LandVerified { - land_id: u256, - verifier: ContractAddress, - } - - #[derive(Drop, Serde, starknet::Store)] - struct Land { - owner: ContractAddress, - location: felt252, - area: u256, - land_use: felt252, - is_registered: bool, - is_verified: bool, - last_transaction_timestamp: u64, - } - - #[storage] - struct Storage { - lands: LegacyMap, - owner_lands: LMap>, - owner_land_count: LegacyMap, - land_nft: ContractAddress, - } - - #[derive(Drop, Serde, starknet::Store)] - struct LandDetails { - owner: ContractAddress, - area: u256, - location: felt252, - status: felt252, - } -} diff --git a/land_registry/src/models/model_transaction.cairo b/land_registry/src/models/model_transaction.cairo deleted file mode 100644 index a331a712..00000000 --- a/land_registry/src/models/model_transaction.cairo +++ /dev/null @@ -1,38 +0,0 @@ -mod ModelLandTransaction { - use core::starknet::get_caller_address; - use core::starknet::ContractAddress; - use super::LandRegistry; - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - TransactionCreated: TransactionCreated, - } - - #[derive(Drop, starknet::Event)] - struct TransactionCreated { - transaction_id: u256, - land_id: u256, - from_owner: ContractAddress, - to_owner: ContractAddress, - transaction_type: u8, - } - - #[derive(Storage)] - struct Transaction { - land_id: u256, - from_owner: ContractAddress, - to_owner: ContractAddress, - transaction_type: u8, - status: u8, - initiation_date: u64, - completion_date: u64, - } - - #[storage] - struct Storage { - transactions: Map, - transaction_count: u256, - land_registry: ContractAddress, - } -} diff --git a/land_registry/src/models/model_verification.cairo b/land_registry/src/models/model_verification.cairo deleted file mode 100644 index a965baff..00000000 --- a/land_registry/src/models/model_verification.cairo +++ /dev/null @@ -1,7 +0,0 @@ -mod ModelVerification { - #[storage] - struct Storage { - land_registry: ContractAddress, - verifiers: LegacyMap, - } -} diff --git a/land_registry/src/tests/test_land_registry.cairo b/land_registry/src/tests/test_land_registry.cairo new file mode 100644 index 00000000..e0a60c47 --- /dev/null +++ b/land_registry/src/tests/test_land_registry.cairo @@ -0,0 +1,110 @@ +use starknet::ContractAddress; +use starknet::testing::{set_caller_address, set_contract_address}; +use land_registry::contracts::LandRegistry::{LandRegistry, ILandRegistryDispatcher, ILandRegistryDispatcherTrait}; +use land_registry::contracts::LandNFT::{LandNFT, ILandNFTDispatcher, ILandNFTDispatcherTrait}; + +// Helper function to deploy contracts +fn deploy_contracts() -> (ILandRegistryDispatcher, ILandNFTDispatcher) { + // Deploy LandNFT + let land_nft = LandNFT::constructor( + 'LandNFT', + 'LNFT', + starknet::contract_address_const::<0x1>() + ); + let land_nft_address = land_nft.contract_address; + + // Deploy LandRegistry + let land_registry = LandRegistry::constructor( + starknet::contract_address_const::<0x2>(), + land_nft_address + ); + let land_registry_address = land_registry.contract_address; + + // Update LandNFT's land_registry + land_nft.set_land_registry(land_registry_address); + + ( + ILandRegistryDispatcher { contract_address: land_registry_address }, + ILandNFTDispatcher { contract_address: land_nft_address } + ) +} + +#[test] +fn test_register_land() { + let (land_registry, land_nft) = deploy_contracts(); + + // Set caller as the land registry contract + set_caller_address(land_registry.contract_address); + + let owner = starknet::contract_address_const::<0x3>(); + let location = 'New York'; + let area = 1000; + let land_use = 'Residential'; + let document_hash = 'QmHash123'; + + let land_id = land_registry.register_land(owner, location, area, land_use, document_hash); + + assert(land_id == 1, 'Invalid land ID'); + + let land_details = land_nft.get_land_details(land_id); + assert(land_details.location == location, 'Invalid location'); + assert(land_details.area == area, 'Invalid area'); + assert(land_details.land_use == land_use, 'Invalid land use'); + assert(land_details.document_hash == document_hash, 'Invalid document hash'); + assert(!land_details.is_verified, 'Land should not be verified'); +} + +#[test] +fn test_transfer_land() { + let (land_registry, land_nft) = deploy_contracts(); + + // Register land + set_caller_address(land_registry.contract_address); + let original_owner = starknet::contract_address_const::<0x3>(); + let land_id = land_registry.register_land(original_owner, 'New York', 1000, 'Residential', 'QmHash123'); + + // Transfer land + let new_owner = starknet::contract_address_const::<0x4>(); + set_caller_address(original_owner); + land_registry.transfer_land(land_id, new_owner); + + // Check new owner + assert(land_nft.owner_of(land_id) == new_owner, 'Land transfer failed'); +} + +#[test] +fn test_verify_land() { + let (land_registry, land_nft) = deploy_contracts(); + + // Register land + set_caller_address(land_registry.contract_address); + let owner = starknet::contract_address_const::<0x3>(); + let land_id = land_registry.register_land(owner, 'New York', 1000, 'Residential', 'QmHash123'); + + // Verify land + let verifier = starknet::contract_address_const::<0x2>(); + set_caller_address(verifier); + land_registry.verify_land(land_id, verifier); + + // Check verification status + let land_details = land_nft.get_land_details(land_id); + assert(land_details.is_verified, 'Land should be verified'); +} + +#[test] +fn test_get_owner_lands() { + let (land_registry, land_nft) = deploy_contracts(); + + // Register multiple lands for the same owner + set_caller_address(land_registry.contract_address); + let owner = starknet::contract_address_const::<0x3>(); + let land_id1 = land_registry.register_land(owner, 'New York', 1000, 'Residential', 'QmHash123'); + let land_id2 = land_registry.register_land(owner, 'Los Angeles', 1500, 'Commercial', 'QmHash456'); + + // Get owner lands + let owner_lands = land_registry.get_owner_lands(owner); + + assert(owner_lands.len() == 2, 'Invalid number of owner lands'); + assert(*owner_lands.at(0) == land_id1, 'Invalid land ID 1'); + assert(*owner_lands.at(1) == land_id2, 'Invalid land ID 2'); +} \ No newline at end of file diff --git a/land_registry/src/traits/ILandHolder.cairo b/land_registry/src/traits/ILandHolder.cairo deleted file mode 100644 index f7fbf27f..00000000 --- a/land_registry/src/traits/ILandHolder.cairo +++ /dev/null @@ -1,22 +0,0 @@ -use core::starknet::ContractAddress; -#[starknet::interface] -pub trait ILandHolder { - fn get_registered_land( - self: @TContractState, land_id: u256, contract_address: ContractAddress - ) -> Option; - - - fn get_all_registered_lands( - self: @TContractState, owner_address: Address - ) -> Array; - - fn check_land_ownership( - self: @TContractState, land_id: u256, contract_address: ContractAddress - ) -> bool; - fn update_land_document( - ref self: TContractState, land_id: u256, contract_address: ContractAddress - ); - fn remove_registered_land( - ref self: TContractState, land_id: u256, contract_address: ContractAddress - ); -} diff --git a/land_registry/src/traits/ILandInspector.cairo b/land_registry/src/traits/ILandInspector.cairo deleted file mode 100644 index 6fa01d98..00000000 --- a/land_registry/src/traits/ILandInspector.cairo +++ /dev/null @@ -1,13 +0,0 @@ -use core::starknet::ContractAddress; - -#[starknet::interface] -trait ILandInspector { - fn receive_land_request(ref self: ContractState, land_id: u256); - fn view_land(self: @ContractState, land_id: u256) -> LandDetails; - fn approve_land_request(ref self: ContractState, land_id: u256); - fn reject_land_request(ref self: ContractState, land_id: u256, reason: felt252); - fn delete_land_request(ref self: TContractState, land_id: u256); - fn get_pending_requests(self: @ContractState) -> Array; - fn is_inspector(self: @ContractState, address: ContractAddress) -> bool; -} - diff --git a/land_registry/src/traits/ILandNFT.cairo b/land_registry/src/traits/ILandNFT.cairo deleted file mode 100644 index 4b77e879..00000000 --- a/land_registry/src/traits/ILandNFT.cairo +++ /dev/null @@ -1,40 +0,0 @@ -use core::starknet::ContractAddress; -use super::ModelNFT::LandDetails; - -#[starknet::interface] -trait ILandNFT { - fn mint_land( - ref self: TContractState, - to: ContractAddress, - token_id: u256, - location: felt252, - area: u256, - land_use: felt252, - document_hash: felt252 - ); - - fn update_land_details( - ref self: TContractState, - token_id: u256, - location: felt252, - area: u256, - land_use: felt252, - is_verified: bool, - document_hash: felt252 - ); - - fn get_land_details(self: @TContractState, token_id: u256) -> LandDetails; - - // ERC721 functions - fn balance_of(self: @TContractState, account: ContractAddress) -> u256; - fn owner_of(self: @TContractState, token_id: u256) -> ContractAddress; - fn transfer_from( - ref self: TContractState, from: ContractAddress, to: ContractAddress, token_id: u256 - ); - fn approve(ref self: TContractState, to: ContractAddress, token_id: u256); - fn get_approved(self: @TContractState, token_id: u256) -> ContractAddress; - fn set_approval_for_all(ref self: TContractState, operator: ContractAddress, approved: bool); - fn is_approved_for_all( - self: @TContractState, owner: ContractAddress, operator: ContractAddress - ) -> bool; -} diff --git a/land_registry/src/traits/ILandRegistry.cairo b/land_registry/src/traits/ILandRegistry.cairo deleted file mode 100644 index 8318ffa4..00000000 --- a/land_registry/src/traits/ILandRegistry.cairo +++ /dev/null @@ -1,8 +0,0 @@ -use core::starknet::ContractAddress; -#[starknet::interface] -trait ILandRegistry { - fn verify_land(self: @TContractState, land_id: u256, verifier: ContractAddress); - fn register_land( - ref self: TContractState, land_id: u256, owner: ContractAddress - ) -> LandDetails; -} diff --git a/land_registry/src/traits/ILandTransaction.cairo b/land_registry/src/traits/ILandTransaction.cairo deleted file mode 100644 index 371a5dff..00000000 --- a/land_registry/src/traits/ILandTransaction.cairo +++ /dev/null @@ -1,20 +0,0 @@ -use core::starknet::ContractAddress; - -#[starknet::interface] -pub trait ILandInspector { - fn recive_land_request(ref self: ContractState, land_id: u256); - fn view_land(self: @ContractState, land_id: u256); - fn approve_land_request(ref self: ContractState, land_id: u256); - fn reject_land_request(ref self: ContractState, land_id: u256); - fn delete_land_request(ref self: ContractState, land_id: u256); -} - -#[starknet::interface] -pub trait ILandTransaction { - fn create_transaction(ref self: ContractState, land_id: u256, from_owner: ContractAddress, to_owner: ContractAddress, transaction_type: u8) -> u256; - fn get_transaction(self: @ContractState, transaction_id: u256); - fn get_all_transactions(self: @ContractState); - fn get_transactions_by_land_id(self: @ContractState, land_id: u256); - fn get_transactions_by_owner(self: @ContractState, owner: ContractAddress); - fn get_transactions_by_type(self: @ContractState, transaction_type: u8); -} diff --git a/land_registry/src/traits/ILandVerification.cairo b/land_registry/src/traits/ILandVerification.cairo deleted file mode 100644 index 0deb4a43..00000000 --- a/land_registry/src/traits/ILandVerification.cairo +++ /dev/null @@ -1,22 +0,0 @@ -use core::starknet::ContractAddress; -#[starknet::interface] -pub trait ILandVerifier { - // Function signature for land verification - fn verify_land(self: @ContractState, land_id: u256, verifier: ContractAddress); - - // Function signature for rejecting land verification - fn reject_land_verification(self: @ContractState, land_id: u256, verifier: ContractAddress); - - // Function signature for getting land verification status - fn get_land_verification_status(self: @ContractState, land_id: u256) -> bool; - - // Function signature for getting the land verifier address - fn get_land_verifier(self: @ContractState, land_id: u256) -> ContractAddress; - - // Function signature for getting land verification timestamp - fn get_land_verification_timestamp(self: @ContractState, land_id: u256) -> u64; - - // Function signature for getting the reason for land verification - fn get_land_verification_reason(self: @ContractState, land_id: u256) -> felt252; -} - From 7edc50158c252bc8724b5ed0d31c2196a3badbc8 Mon Sep 17 00:00:00 2001 From: Fishon Amos Date: Wed, 9 Oct 2024 10:23:27 +0100 Subject: [PATCH 4/5] feat: land regsitry contract --- land_registry/src/contracts/LandNFT.cairo | 133 ------------------ .../src/contracts/LandRegistry.cairo | 113 ++++----------- land_registry/src/lib.cairo | 15 -- .../src/tests/test_land_registry.cairo | 110 --------------- 4 files changed, 30 insertions(+), 341 deletions(-) delete mode 100644 land_registry/src/contracts/LandNFT.cairo diff --git a/land_registry/src/contracts/LandNFT.cairo b/land_registry/src/contracts/LandNFT.cairo deleted file mode 100644 index ac5c1715..00000000 --- a/land_registry/src/contracts/LandNFT.cairo +++ /dev/null @@ -1,133 +0,0 @@ -use core::starknet::ContractAddress; -use super land_registry::LandDetails; - -#[starknet::interface] - -pub trait ILandNFT { - fn mint_land( - ref self: TContractState, - to: ContractAddress, - token_id: u256, - location: felt252, - area: u256, - land_use: felt252, - document_hash: felt252 - ); - fn verify_land(ref self: TContractState, token_id: u256, verifier: ContractAddress); - fn get_land_details(self: @TContractState, token_id: u256) -> LandDetails; - fn get_owner_lands(self: @TContractState, owner: ContractAddress) -> Array; -} - -#[starknet::contract] -pub mod LandNFT { - use starknet::ContractAddress; - use openzeppelin::token::erc721::ERC721; - use openzeppelin::access::ownable::OwnableComponent; - use starknet::storage::Map; - - #[storage] - struct Storage { - land_registry: ContractAddress, - land_details: Map, - owner_lands: Map>, - } - - #[derive(Drop, Serde, starknet::Store)] - pub struct LandDetails { - location: felt252, - area: u256, - land_use: felt252, - is_verified: bool, - document_hash: felt252, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - LandMinted: LandMinted, - LandVerified: LandVerified, - } - - #[derive(Drop, starknet::Event)] - struct LandMinted { - token_id: u256, - owner: ContractAddress, - } - - #[derive(Drop, starknet::Event)] - struct LandVerified { - token_id: u256, - verifier: ContractAddress, - } - - #[constructor] - fn constructor( - ref self: ContractState, - name: felt252, - symbol: felt252, - land_registry: ContractAddress - ) { - self.initializer(name, symbol); - self.land_registry.write(land_registry); - self._transfer_ownership(land_registry); - } - - #[external(v0)] - - impl LandNFTImpl of ILandNFT { - fn mint_land( - ref self: ContractState, - to: ContractAddress, - token_id: u256, - location: felt252, - area: u256, - land_use: felt252, - document_hash: felt252 - ) { - self.assert_only_owner(); - - self._mint(to, token_id); - - let land_details = LandDetails { - location, - area, - land_use, - is_verified: false, - document_hash, - }; - self.land_details.write(token_id, land_details); - - let mut owner_lands = self.owner_lands.read(to); - owner_lands.append(token_id); - self.owner_lands.write(to, owner_lands); - - self.emit(LandMinted { token_id, owner: to }); - } - - fn verify_land(ref self: ContractState, token_id: u256, verifier: ContractAddress) { - self.assert_only_owner(); - - let mut land_details = self.land_details.read(token_id); - land_details.is_verified = true; - self.land_details.write(token_id, land_details); - - self.emit(LandVerified { token_id, verifier }); - } - - fn get_land_details(self: @ContractState, token_id: u256) -> LandDetails { - self.land_details.read(token_id) - } - - fn get_owner_lands(self: @ContractState, owner: ContractAddress) -> Array { - self.owner_lands.read(owner) - } - } - - #[generate_trait] - impl PrivateMethods of PrivateMethodsTrait { - fn assert_only_owner(self: @ContractState) { - let caller = starknet::get_caller_address(); - assert(caller == self.land_registry.read(), 'Only LandRegistry can call'); - } - } -} diff --git a/land_registry/src/contracts/LandRegistry.cairo b/land_registry/src/contracts/LandRegistry.cairo index 134274bb..e9ee065f 100644 --- a/land_registry/src/contracts/LandRegistry.cairo +++ b/land_registry/src/contracts/LandRegistry.cairo @@ -1,4 +1,4 @@ -use starknet::ContractAddress; +use core::starknet::ContractAddress; #[starknet::interface] trait ILandRegistry { @@ -7,38 +7,45 @@ trait ILandRegistry { owner: ContractAddress, location: felt252, area: u256, - land_use: felt252, - document_hash: felt252 + land_use: LandRegistry::LandUse, ) -> u256; fn transfer_land(ref self: TContractState, land_id: u256, new_owner: ContractAddress); - fn verify_land(ref self: TContractState, land_id: u256, verifier: ContractAddress); - fn get_land_details(self: @TContractState, land_id: u256) -> Land; + fn verify_land(ref self: TContractState, land_id: u256) -> LandRegistry::Land; fn get_owner_lands(self: @TContractState, owner: ContractAddress) -> Array; -} - -#[derive(Drop, Serde, starknet::Store)] -struct Land { - owner: ContractAddress, - location: felt252, - area: u256, - land_use: felt252, - is_verified: bool, - last_transaction_timestamp: u64, - document_hash: felt252, + fn update_land(ref self: TContractState, owner: ContractAddress, land_id: u256) -> Land; } #[starknet::contract] mod LandRegistry { - use super::{ILandRegistry, Land, ContractAddress}; - use starknet::{get_caller_address, get_block_timestamp}; - use land_registry::contracts::LandNFT::{ILandNFTDispatcher, ILandNFTDispatcherTrait}; - use starknet::storage::Map; + use super::ILandRegistry; + use core::array::ArrayTrait; + use core::starknet::{ContractAddress, get_caller_address, get_block_timestamp}; + use core::starknet::storage::{ + Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess + }; #[storage] struct Storage { - land_nft: ILandNFTDispatcher, - verifiers: Map, - next_land_id: u256, + lands: Map, + owners: Map>, + } + + #[derive(Drop, Serde, starknet::Store)] + pub struct Land { + owner: ContractAddress, + location: felt252, + area: u256, + land_use: felt252, + is_verified: bool, + last_transaction_timestamp: u64, + } + + enum LandUse { + Residential, + Commercial, + Industrial, + Recreational, + Agricultural, } #[event] @@ -65,64 +72,4 @@ mod LandRegistry { to_owner: ContractAddress, } - #[derive(Drop, starknet::Event)] - struct LandVerified { - land_id: u256, - verifier: ContractAddress, - } - - #[constructor] - fn constructor(ref self: ContractState, initial_verifier: ContractAddress, land_nft_address: ContractAddress) { - self.verifiers.write(initial_verifier, true); - self.land_nft.write(ILandNFTDispatcher { contract_address: land_nft_address }); - self.next_land_id.write(1); - } - - #[external(v0)] - #abi_embedV0 - impl LandRegistryImpl of ILandRegistry { - fn register_land( - ref self: ContractState, - owner: ContractAddress, - location: felt252, - area: u256, - land_use: felt252, - document_hash: felt252 - ) -> u256 { - let land_id = self.next_land_id.read(); - self.next_land_id.write(land_id + 1); - - self.land_nft.read().mint_land(owner, land_id, location, area, land_use, document_hash); - - self.emit(LandRegistered { land_id, owner, location, area, land_use }); - - land_id - } - - fn transfer_land(ref self: ContractState, land_id: u256, new_owner: ContractAddress) { - let caller = get_caller_address(); - let current_owner = self.land_nft.read().owner_of(land_id); - assert(current_owner == caller, 'Only the current owner can transfer'); - - self.land_nft.read().transfer_from(caller, new_owner, land_id); - - self.emit(LandTransferred { land_id, from_owner: caller, to_owner: new_owner }); - } - - fn verify_land(ref self: ContractState, land_id: u256, verifier: ContractAddress) { - assert(self.verifiers.read(verifier), 'Not an authorized verifier'); - - self.land_nft.read().verify_land(land_id, verifier); - - self.emit(LandVerified { land_id, verifier }); - } - - fn get_land_details(self: @ContractState, land_id: u256) -> Land { - self.land_nft.read().get_land_details(land_id) - } - - fn get_owner_lands(self: @ContractState, owner: ContractAddress) -> Array { - self.land_nft.read().get_owner_lands(owner) - } - } } \ No newline at end of file diff --git a/land_registry/src/lib.cairo b/land_registry/src/lib.cairo index a3a1654d..e69de29b 100644 --- a/land_registry/src/lib.cairo +++ b/land_registry/src/lib.cairo @@ -1,15 +0,0 @@ -mod contracts { - mod LandRegistry; - mod LandNFT; -} - -mod tests { - mod test_land_registry; -} - -use contracts::LandRegistry::{LandRegistry, ILandRegistry, ILandRegistryDispatcher, ILandRegistryDispatcherTrait}; -use contracts::LandNFT::{LandNFT, ILandNFT, ILandNFTDispatcher, ILandNFTDispatcherTrait}; - -use contracts::LandRegistry::Land; -use contracts::LandNFT::LandDetails; - diff --git a/land_registry/src/tests/test_land_registry.cairo b/land_registry/src/tests/test_land_registry.cairo index e0a60c47..e69de29b 100644 --- a/land_registry/src/tests/test_land_registry.cairo +++ b/land_registry/src/tests/test_land_registry.cairo @@ -1,110 +0,0 @@ -use starknet::ContractAddress; -use starknet::testing::{set_caller_address, set_contract_address}; -use land_registry::contracts::LandRegistry::{LandRegistry, ILandRegistryDispatcher, ILandRegistryDispatcherTrait}; -use land_registry::contracts::LandNFT::{LandNFT, ILandNFTDispatcher, ILandNFTDispatcherTrait}; - -// Helper function to deploy contracts -fn deploy_contracts() -> (ILandRegistryDispatcher, ILandNFTDispatcher) { - // Deploy LandNFT - let land_nft = LandNFT::constructor( - 'LandNFT', - 'LNFT', - starknet::contract_address_const::<0x1>() - ); - let land_nft_address = land_nft.contract_address; - - // Deploy LandRegistry - let land_registry = LandRegistry::constructor( - starknet::contract_address_const::<0x2>(), - land_nft_address - ); - let land_registry_address = land_registry.contract_address; - - // Update LandNFT's land_registry - land_nft.set_land_registry(land_registry_address); - - ( - ILandRegistryDispatcher { contract_address: land_registry_address }, - ILandNFTDispatcher { contract_address: land_nft_address } - ) -} - -#[test] -fn test_register_land() { - let (land_registry, land_nft) = deploy_contracts(); - - // Set caller as the land registry contract - set_caller_address(land_registry.contract_address); - - let owner = starknet::contract_address_const::<0x3>(); - let location = 'New York'; - let area = 1000; - let land_use = 'Residential'; - let document_hash = 'QmHash123'; - - let land_id = land_registry.register_land(owner, location, area, land_use, document_hash); - - assert(land_id == 1, 'Invalid land ID'); - - let land_details = land_nft.get_land_details(land_id); - assert(land_details.location == location, 'Invalid location'); - assert(land_details.area == area, 'Invalid area'); - assert(land_details.land_use == land_use, 'Invalid land use'); - assert(land_details.document_hash == document_hash, 'Invalid document hash'); - assert(!land_details.is_verified, 'Land should not be verified'); -} - -#[test] -fn test_transfer_land() { - let (land_registry, land_nft) = deploy_contracts(); - - // Register land - set_caller_address(land_registry.contract_address); - let original_owner = starknet::contract_address_const::<0x3>(); - let land_id = land_registry.register_land(original_owner, 'New York', 1000, 'Residential', 'QmHash123'); - - // Transfer land - let new_owner = starknet::contract_address_const::<0x4>(); - set_caller_address(original_owner); - land_registry.transfer_land(land_id, new_owner); - - // Check new owner - assert(land_nft.owner_of(land_id) == new_owner, 'Land transfer failed'); -} - -#[test] -fn test_verify_land() { - let (land_registry, land_nft) = deploy_contracts(); - - // Register land - set_caller_address(land_registry.contract_address); - let owner = starknet::contract_address_const::<0x3>(); - let land_id = land_registry.register_land(owner, 'New York', 1000, 'Residential', 'QmHash123'); - - // Verify land - let verifier = starknet::contract_address_const::<0x2>(); - set_caller_address(verifier); - land_registry.verify_land(land_id, verifier); - - // Check verification status - let land_details = land_nft.get_land_details(land_id); - assert(land_details.is_verified, 'Land should be verified'); -} - -#[test] -fn test_get_owner_lands() { - let (land_registry, land_nft) = deploy_contracts(); - - // Register multiple lands for the same owner - set_caller_address(land_registry.contract_address); - let owner = starknet::contract_address_const::<0x3>(); - let land_id1 = land_registry.register_land(owner, 'New York', 1000, 'Residential', 'QmHash123'); - let land_id2 = land_registry.register_land(owner, 'Los Angeles', 1500, 'Commercial', 'QmHash456'); - - // Get owner lands - let owner_lands = land_registry.get_owner_lands(owner); - - assert(owner_lands.len() == 2, 'Invalid number of owner lands'); - assert(*owner_lands.at(0) == land_id1, 'Invalid land ID 1'); - assert(*owner_lands.at(1) == land_id2, 'Invalid land ID 2'); -} \ No newline at end of file From 0619532f41d39a9e6793f98e9a39c54a4dbd8636 Mon Sep 17 00:00:00 2001 From: Fishon Amos Date: Thu, 10 Oct 2024 11:41:16 +0100 Subject: [PATCH 5/5] feat: land regsitry -- register land function --- .../src/contracts/LandRegistry.cairo | 62 ++++++++++++++++++- land_registry/src/lib.cairo | 1 + .../src/tests/test_land_registry.cairo | 1 + 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/land_registry/src/contracts/LandRegistry.cairo b/land_registry/src/contracts/LandRegistry.cairo index e9ee065f..221c5485 100644 --- a/land_registry/src/contracts/LandRegistry.cairo +++ b/land_registry/src/contracts/LandRegistry.cairo @@ -35,7 +35,7 @@ mod LandRegistry { owner: ContractAddress, location: felt252, area: u256, - land_use: felt252, + land_use: LandUse, is_verified: bool, last_transaction_timestamp: u64, } @@ -72,4 +72,62 @@ mod LandRegistry { to_owner: ContractAddress, } -} \ No newline at end of file + #[Contructor] + fn contructor(ref self: TContractSatate, deployer: ContractAddress) { + let deployer_address = get_caller_address(); + emit!(ContractDeployed { deployer: deployer_address, }); + } + #[derive(Drop)] + struct Location { + latitude: f64, + longitude: f64, + } + + #[abi(embed_v0)] + impl LandRegistryImpl of ILandRegistry { + fn register_land( + ref self: TContractState, + owner: OwnerAddress, + location: Location, + area: u256, + land_use: LandUse, + ) -> u256 { + //we will use the block time stamp as the landid for now. + let mut timestamp = get_block_timestamp(); + let land_id: u256 = timestamp.into(); + let new_land = Land { + owner: OwnerAddress, + location: location, + area: area, + land_use: LandUse, + landid: landid, + }; + + //store the land in the lands map.. + let result = self.lands.insert(land_id, new_land); + + // Add the land Id the list of owner lands by for an owner such that we can retrieve all + // the lands for a specific owner + let owner_lands = self.owner_lands.entry(owner).or_insert(Vec::new()); + + //Emit events for land registered. This will help use to track registered lands + + //How can we get owner lands? + + emit!( + LandRegistered { + land_id: u256, + owner: ContractAddress, + location: felt252, + area: u256, + land_use: felt252, + } + ); + + //finally return the landID + land_id + + println!('You land has been succcessfully registered {:?}', result) + } + } +} diff --git a/land_registry/src/lib.cairo b/land_registry/src/lib.cairo index e69de29b..8b137891 100644 --- a/land_registry/src/lib.cairo +++ b/land_registry/src/lib.cairo @@ -0,0 +1 @@ + diff --git a/land_registry/src/tests/test_land_registry.cairo b/land_registry/src/tests/test_land_registry.cairo index e69de29b..8b137891 100644 --- a/land_registry/src/tests/test_land_registry.cairo +++ b/land_registry/src/tests/test_land_registry.cairo @@ -0,0 +1 @@ +