Skip to content

Commit

Permalink
Merge pull request #13 from starknet-id/feat/add_ccip
Browse files Browse the repository at this point in the history
feat: add hint
  • Loading branch information
Th0rgal authored Nov 7, 2023
2 parents 5232af6 + 2522e20 commit b9bb094
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 23 deletions.
10 changes: 8 additions & 2 deletions src/interface/naming.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ use naming::naming::main::Naming::{Discount, DomainData};
#[starknet::interface]
trait INaming<TContractState> {
// view
fn resolve(self: @TContractState, domain: Span<felt252>, field: felt252) -> felt252;
fn resolve(
self: @TContractState, domain: Span<felt252>, field: felt252, hint: Span<felt252>
) -> felt252;

fn domain_to_data(self: @TContractState, domain: Span<felt252>) -> DomainData;

fn domain_to_id(self: @TContractState, domain: Span<felt252>) -> u128;

fn domain_to_address(self: @TContractState, domain: Span<felt252>) -> ContractAddress;
fn domain_to_address(
self: @TContractState, domain: Span<felt252>, hint: Span<felt252>
) -> ContractAddress;

fn address_to_domain(self: @TContractState, address: ContractAddress) -> Span<felt252>;

Expand Down Expand Up @@ -43,6 +47,8 @@ trait INaming<TContractState> {

fn reset_address_to_domain(ref self: TContractState);

fn set_domain_to_resolver(ref self: TContractState, domain: Span<felt252>, resolver: ContractAddress);

// admin
fn set_admin(ref self: TContractState, new_admin: ContractAddress);

Expand Down
4 changes: 3 additions & 1 deletion src/interface/resolver.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ use starknet::ContractAddress;

#[starknet::interface]
trait IResolver<TContractState> {
fn resolve(self: @TContractState, domain: Span<felt252>, field: felt252) -> felt252;
fn resolve(
self: @TContractState, domain: Span<felt252>, field: felt252, hint: Span<felt252>
) -> felt252;
}
4 changes: 2 additions & 2 deletions src/naming/internal.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,14 @@ impl InternalImpl of InternalTrait {

// returns domain_hash (or zero) and its value for a specific field
fn resolve_util(
self: @Naming::ContractState, domain: Span<felt252>, field: felt252
self: @Naming::ContractState, domain: Span<felt252>, field: felt252, hint: Span<felt252>
) -> (felt252, felt252) {
let (resolver, parent_start) = self.domain_to_resolver(domain, 1);
if (resolver != ContractAddressZeroable::zero()) {
(
0,
IResolverDispatcher { contract_address: resolver }
.resolve(domain.slice(0, parent_start), field)
.resolve(domain.slice(0, parent_start), field, hint)
)
} else {
let hashed_domain = self.hash_domain(domain);
Expand Down
45 changes: 38 additions & 7 deletions src/naming/main.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -148,17 +148,21 @@ mod Naming {
// For example, it allows to find the Bitcoin address of Alice.stark by calling
// naming.resolve(['alice'], 'bitcoin')
// Use it with caution in smartcontracts as it can call untrusted contracts
fn resolve(self: @ContractState, domain: Span<felt252>, field: felt252) -> felt252 {
let (_, value) = self.resolve_util(domain, field);
fn resolve(
self: @ContractState, domain: Span<felt252>, field: felt252, hint: Span<felt252>
) -> felt252 {
let (_, value) = self.resolve_util(domain, field, hint);
value
}

// This functions allows to resolve a domain to a native address. Its output is designed
// to be used as a parameter for other functions (for example if you want to send ERC20
// to a .stark)
fn domain_to_address(self: @ContractState, domain: Span<felt252>) -> ContractAddress {
fn domain_to_address(
self: @ContractState, domain: Span<felt252>, hint: Span<felt252>
) -> ContractAddress {
// resolve must be performed first because it calls untrusted resolving contracts
let (hashed_domain, value) = self.resolve_util(domain, 'starknet');
let (hashed_domain, value) = self.resolve_util(domain, 'starknet', hint);
if value != 0 {
let addr: Option<ContractAddress> = value.try_into();
return addr.unwrap();
Expand Down Expand Up @@ -204,7 +208,8 @@ mod Naming {
fn address_to_domain(self: @ContractState, address: ContractAddress) -> Span<felt252> {
let mut domain = ArrayTrait::new();
self.read_address_to_domain(address, ref domain);
if domain.len() != 0 && self.domain_to_address(domain.span()) == address {
if domain.len() != 0
&& self.domain_to_address(domain.span(), array![].span()) == address {
domain.span()
} else {
let identity = IIdentityDispatcher {
Expand All @@ -215,7 +220,10 @@ mod Naming {
let id_hashed_domain = identity
.get_verifier_data(id, 'name', get_contract_address(), 0);
let domain = self.unhash_domain(id_hashed_domain);
assert(self.domain_to_address(domain) == address, 'domain not pointing back');
assert(
self.domain_to_address(domain, array![].span()) == address,
'domain not pointing back'
);
domain
}
}
Expand Down Expand Up @@ -356,7 +364,10 @@ mod Naming {
// will override your main id
fn set_address_to_domain(ref self: ContractState, domain: Span<felt252>) {
let address = get_caller_address();
assert(self.domain_to_address(domain) == address, 'domain not pointing back');
assert(
self.domain_to_address(domain, array![].span()) == address,
'domain not pointing back'
);
self.emit(Event::AddressToDomainUpdate(AddressToDomainUpdate { address, domain }));
self.set_address_to_domain_util(address, domain);
}
Expand All @@ -372,6 +383,26 @@ mod Naming {
self.set_address_to_domain_util(address, array![0].span());
}

fn set_domain_to_resolver(
ref self: ContractState, domain: Span<felt252>, resolver: ContractAddress
) {
self.assert_control_domain(domain, get_caller_address());

// Write domain owner
let hashed_domain = self.hash_domain(domain);
let current_domain_data = self._domain_data.read(hashed_domain);
let new_domain_data = DomainData {
owner: current_domain_data.owner,
resolver,
address: current_domain_data.address,
expiry: current_domain_data.expiry,
key: current_domain_data.key,
parent_key: current_domain_data.parent_key,
};
self._domain_data.write(hashed_domain, new_domain_data);
self.emit(Event::DomainResolverUpdate(DomainResolverUpdate { domain, resolver }));
}

// ADMIN

fn set_admin(ref self: ContractState, new_admin: ContractAddress) {
Expand Down
10 changes: 6 additions & 4 deletions src/tests/naming/test_custom_resolver.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ mod CustomResolver {

#[external(v0)]
impl AdditionResolveImpl of IResolver<ContractState> {
fn resolve(self: @ContractState, mut domain: Span<felt252>, field: felt252) -> felt252 {
fn resolve(
self: @ContractState, mut domain: Span<felt252>, field: felt252, hint: Span<felt252>
) -> felt252 {
let mut output = 0;
loop {
match domain.pop_front() {
Expand Down Expand Up @@ -88,12 +90,12 @@ fn test_custom_resolver() {

let domain = array![th0rgal].span();
// by default we should have nothing written
assert(naming.resolve(domain, 'starknet') == 0, 'non empty starknet field');
assert(naming.resolve(domain, 'starknet', array![].span()) == 0, 'non empty starknet field');
// so it should resolve to the starknetid owner
assert(naming.domain_to_address(domain) == caller, 'wrong domain target');
assert(naming.domain_to_address(domain, array![].span()) == caller, 'wrong domain target');

let domain = array![1, 2, 3, th0rgal].span();

// let's try the resolving
assert(naming.resolve(domain, 'starknet') == 1 + 2 + 3, 'wrong target');
assert(naming.resolve(domain, 'starknet', array![].span()) == 1 + 2 + 3, 'wrong target');
}
7 changes: 5 additions & 2 deletions src/tests/naming/test_features.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ fn test_subdomains() {
// we transfer hello.th0rgal.stark to id2
naming.transfer_domain(subdomain, id2);

assert(naming.domain_to_address(subdomain) == caller, 'wrong subdomain initial target');
assert(
naming.domain_to_address(subdomain, array![].span()) == caller,
'wrong subdomain initial target'
);

// and make sure the owner has been updated
assert(naming.domain_to_id(subdomain) == id2, 'owner not updated correctly');
Expand All @@ -78,7 +81,7 @@ fn test_subdomains() {

// ensure the subdomain was reset
assert(
naming.domain_to_address(subdomain) == ContractAddressZeroable::zero(),
naming.domain_to_address(subdomain, array![].span()) == ContractAddressZeroable::zero(),
'target not updated correctly'
);
}
Expand Down
44 changes: 39 additions & 5 deletions src/tests/naming/test_usecases.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ fn test_basic_usage() {
// let's try the resolving
let domain = array![th0rgal].span();
// by default we should have nothing written
assert(naming.resolve(domain, 'starknet') == 0, 'non empty starknet field');
assert(naming.resolve(domain, 'starknet', array![].span()) == 0, 'non empty starknet field');
// so it should resolve to the starknetid owner
assert(naming.domain_to_address(domain) == caller, 'wrong domain target');
assert(naming.domain_to_address(domain, array![].span()) == caller, 'wrong domain target');

// let's try reverse resolving
identity.set_main_id(id);
Expand All @@ -65,9 +65,12 @@ fn test_basic_usage() {
identity.set_user_data(id, 'starknet', new_target.into(), 0);

// now we should have nothing written
assert(naming.resolve(domain, 'starknet') == new_target.into(), 'wrong starknet field');
assert(
naming.resolve(domain, 'starknet', array![].span()) == new_target.into(),
'wrong starknet field'
);
// and it should resolve to the new domain target
assert(naming.domain_to_address(domain) == new_target, 'wrong domain target');
assert(naming.domain_to_address(domain, array![].span()) == new_target, 'wrong domain target');

// testing ownership transfer
let new_id = 2;
Expand Down Expand Up @@ -249,7 +252,9 @@ fn test_set_address_to_domain() {

// let's try the resolving
let first_domain = array![first_domain_top].span();
assert(naming.domain_to_address(first_domain) == caller, 'wrong domain target');
assert(
naming.domain_to_address(first_domain, array![].span()) == caller, 'wrong domain target'
);

// set reverse resolving
identity.set_main_id(id1);
Expand All @@ -267,3 +272,32 @@ fn test_set_address_to_domain() {
let expect_domain1 = naming.address_to_domain(caller);
assert(expect_domain1 == first_domain, 'wrong rev resolving b');
}

#[test]
#[available_gas(2000000000)]
fn test_set_domain_to_resolver() {
// setup
let (eth, pricing, identity, naming) = deploy();
let caller = contract_address_const::<0x123>();
set_contract_address(caller);
let id1: u128 = 1;
let domain: felt252 = 82939898252385817;

//we mint the id
identity.mint(id1);

// buy the domain
let (_, price1) = pricing.compute_buy_price(11, 365);
eth.approve(naming.contract_address, price1);
naming
.buy(
id1, domain, 365, ContractAddressZeroable::zero(), ContractAddressZeroable::zero(), 0, 0
);

// set resolver
let resolver = contract_address_const::<0x456>();
naming.set_domain_to_resolver(array![domain].span(), resolver);

let data = naming.domain_to_data(array![domain].span());
assert(data.resolver == resolver, 'wrong resolver');
}

0 comments on commit b9bb094

Please sign in to comment.