From af6ed6dd0541912d5c04d0970191b5dbf092efad Mon Sep 17 00:00:00 2001 From: Thomas Marchand Date: Sat, 13 Jul 2024 16:48:44 +0100 Subject: [PATCH 1/2] fix: crash on reverse resolving post subdomain transfer --- src/naming/main.cairo | 5 +++ src/tests/naming/test_abuses.cairo | 51 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/naming/main.cairo b/src/naming/main.cairo index 8e1e9ed..e1dc5c8 100644 --- a/src/naming/main.cairo +++ b/src/naming/main.cairo @@ -203,6 +203,9 @@ mod Naming { fn domain_to_address( self: @ContractState, domain: Span, hint: Span ) -> ContractAddress { + if domain.len() == 0 { + return ContractAddressZeroable::zero(); + } let (resolver, parent_length) = self.domain_to_resolver(domain); // if there is a resolver starting from the top if (resolver != ContractAddressZeroable::zero()) { @@ -305,9 +308,11 @@ mod Naming { // self.domain_to_address(domain, array![].span()) == address, // 'domain not pointing back' // ); + println!("echo: {:?}", domain); if self.domain_to_address(domain, array![].span()) != address { return array![].span(); } + println!("hey"); domain } } diff --git a/src/tests/naming/test_abuses.cairo b/src/tests/naming/test_abuses.cairo index ef0a32c..3fa0930 100644 --- a/src/tests/naming/test_abuses.cairo +++ b/src/tests/naming/test_abuses.cairo @@ -409,3 +409,54 @@ fn test_buy_empty_domain() { 0 ); } + + +#[test] +#[available_gas(2000000000)] +fn test_subdomain_reverse() { + // setup + let (eth, pricing, identity, naming) = deploy(); + let alpha = contract_address_const::<0x123>(); + let bravo = contract_address_const::<0x456>(); + let charlie = contract_address_const::<0x789>(); + + // we mint the ids + set_contract_address(alpha); + identity.mint(1); + set_contract_address(bravo); + identity.mint(2); + set_contract_address(charlie); + identity.mint(3); + + set_contract_address(alpha); + let aller: felt252 = 35683102; + + // we check how much a domain costs + let (_, price) = pricing.compute_buy_price(5, 365); + + // we allow the naming to take our money + eth.approve(naming.contract_address, price); + + // we buy with no resolver, no sponsor, no discount and empty metadata + naming + .buy(1, aller, 365, ContractAddressZeroable::zero(), ContractAddressZeroable::zero(), 0, 0); + + let subdomain = array![aller, aller].span(); + + // we transfer aller.aller.stark to id2 + naming.transfer_domain(subdomain, 2); + + // and make sure the owner has been updated + assert(naming.domain_to_id(subdomain) == 2, 'owner not updated correctly'); + set_contract_address(bravo); + let result = naming.address_to_domain(bravo, array![].span()); + assert(result == array![].span(), 'unexpected result'); + // we then set this subdomain as main domain and ensures reverse resolving works + identity.set_main_id(2); + let result = naming.address_to_domain(bravo, array![].span()); + assert(result == subdomain, 'unexpected result'); + // before transfering this subdomain + naming.transfer_domain(subdomain, 3); + let result = naming.address_to_domain(bravo, array![].span()); + assert(result == array![].span(), 'unexpected result'); +} From b23ed6ce780aa3d86e9f42da41c40cd29c37876f Mon Sep 17 00:00:00 2001 From: Thomas Marchand Date: Sat, 13 Jul 2024 17:13:48 +0100 Subject: [PATCH 2/2] feat: add revoke_domain and tests --- src/interface/naming.cairo | 2 + src/naming/main.cairo | 45 ++++++++++++++++++- src/tests/naming/test_abuses.cairo | 72 ++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 2 deletions(-) diff --git a/src/interface/naming.cairo b/src/interface/naming.cairo index e5caf55..c94165e 100644 --- a/src/interface/naming.cairo +++ b/src/interface/naming.cairo @@ -89,6 +89,8 @@ trait INaming { fn reset_subdomains(ref self: TContractState, domain: Span); + fn revoke_domain(ref self: TContractState, domain: Span); + fn set_address_to_domain(ref self: TContractState, domain: Span, hint: Span); fn clear_legacy_domain_to_address(ref self: TContractState, domain: Span); diff --git a/src/naming/main.cairo b/src/naming/main.cairo index e1dc5c8..b70507f 100644 --- a/src/naming/main.cairo +++ b/src/naming/main.cairo @@ -308,11 +308,9 @@ mod Naming { // self.domain_to_address(domain, array![].span()) == address, // 'domain not pointing back' // ); - println!("echo: {:?}", domain); if self.domain_to_address(domain, array![].span()) != address { return array![].span(); } - println!("hey"); domain } } @@ -682,6 +680,49 @@ mod Naming { self.emit(Event::SubdomainsReset(SubdomainsReset { domain: domain, })); } + // this function will reset the native resolving of a domain, + // it is intended to be called by the owner of a parent domain + // who would like to take back a specific subdomain and its + // recursive subdomains but could also be used as a way to burn + // a root domain + fn revoke_domain(ref self: ContractState, domain: Span) { + self.assert_control_domain(domain, get_caller_address()); + let hashed_domain = self.hash_domain(domain); + let current_domain_data = self._domain_data.read(hashed_domain); + let new_domain_data = DomainData { + owner: 0, + resolver: ContractAddressZeroable::zero(), + address: ContractAddressZeroable::zero(), + expiry: current_domain_data.expiry, + key: current_domain_data.key + 1, + parent_key: current_domain_data.parent_key, + }; + self._domain_data.write(hashed_domain, new_domain_data); + if current_domain_data.resolver != new_domain_data.resolver { + self + .emit( + Event::DomainResolverUpdate( + DomainResolverUpdate { + domain, resolver: ContractAddressZeroable::zero() + } + ) + ); + } + if current_domain_data.address != new_domain_data.address { + self.emit(Event::LegacyDomainToAddressClear(LegacyDomainToAddressClear { domain })); + } + self.emit(Event::SubdomainsReset(SubdomainsReset { domain: domain, })); + self + .emit( + Event::DomainTransfer( + DomainTransfer { + domain: domain, + prev_owner: current_domain_data.owner, + new_owner: new_domain_data.owner + } + ) + ); + } // will override your main id fn set_address_to_domain( diff --git a/src/tests/naming/test_abuses.cairo b/src/tests/naming/test_abuses.cairo index 3fa0930..d0746b2 100644 --- a/src/tests/naming/test_abuses.cairo +++ b/src/tests/naming/test_abuses.cairo @@ -460,3 +460,75 @@ fn test_subdomain_reverse() { let result = naming.address_to_domain(bravo, array![].span()); assert(result == array![].span(), 'unexpected result'); } + + +#[test] +#[available_gas(2000000000)] +fn test_use_revoke_domain() { + // setup + let (eth, pricing, identity, naming) = deploy(); + let alpha = contract_address_const::<0x123>(); + let bravo = contract_address_const::<0x456>(); + + // we mint the ids + + set_contract_address(alpha); + identity.mint(1); + set_contract_address(bravo); + identity.mint(2); + + set_contract_address(alpha); + let aller: felt252 = 35683102; + + // we check how much a domain costs + let (_, price) = pricing.compute_buy_price(5, 365); + + // we allow the naming to take our money + eth.approve(naming.contract_address, price); + + // we buy with no resolver, no sponsor, no discount and empty metadata + naming + .buy(1, aller, 365, ContractAddressZeroable::zero(), ContractAddressZeroable::zero(), 0, 0); + + let root_domain = array![aller].span(); + let subdomain = array![aller, aller].span(); + + // we transfer aller.aller.stark to id2 + naming.transfer_domain(subdomain, 2); + + // and make sure the owner has been updated + assert(naming.domain_to_id(subdomain) == 2, 'owner not updated correctly'); + + // now bravo should be able to create a subsubdomain (charlie.aller.aller.stark): + set_contract_address(bravo); + let subsubdomain = array!['charlie', aller, aller].span(); + naming.transfer_domain(subsubdomain, 3); + + // alpha resets subdomains of aller.stark + set_contract_address(alpha); + naming.revoke_domain(subdomain); + + // ensure aller.stark still resolves + assert(naming.domain_to_id(root_domain) == 1, 'owner not updated correctly'); + // ensure the subdomain was reset + assert(naming.domain_to_id(subdomain) == 0, 'target not updated correctly'); + assert( + naming.domain_to_address(subdomain, array![].span()) == ContractAddressZeroable::zero(), + 'owner not updated correctly' + ); + assert( + naming.domain_to_data(subdomain).resolver == ContractAddressZeroable::zero(), + 'resolver not updated correctly' + ); + + // ensure subsubdomain too + assert(naming.domain_to_id(subsubdomain) == 0, 'owner not updated correctly'); + assert( + naming.domain_to_address(subsubdomain, array![].span()) == ContractAddressZeroable::zero(), + 'target not updated correctly' + ); + assert( + naming.domain_to_data(subsubdomain).resolver == ContractAddressZeroable::zero(), + 'resolver not updated correctly' + ); +}