diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..50d5781 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,25 @@ +name: CI Tests + +on: [push, pull_request, pull_request_target] + +env: + SCARB_VERSION: 2.3.1 + +jobs: + scarb-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install scarb + run: | + curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh -s -- -v $SCARB_VERSION + + - name: Install project dependencies + run: scarb fetch + + - name: Compile smart contracts + run: scarb build + + - name: Run scarb tests + run: scarb test -p identity diff --git a/Scarb.toml b/Scarb.toml index b24a074..681134d 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -8,7 +8,8 @@ repository = "https://github.com/starknet-id/identity" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest [dependencies] -starknet = "2.3.0" +starknet = "2.3.1" +openzeppelin = { git = "https://github.com/andrew-fleming/cairo-contracts.git", branch = "component-erc721" } storage_read = { git = "https://github.com/starknet-id/storage_read_component", rev = "c6c69e15d34abfc39ac51dc21b96724e2e19ff31" } custom_uri = { git = "https://github.com/starknet-id/custom_uri_component", rev = "abb2f3d43c7be56dd5cd9f93c33af40b272c2245" } diff --git a/requirements.txt b/requirements.txt index 96c303f..f697596 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ python-dotenv -starknet-py==0.17.1 +starknet-py==0.18.2 case-converter==1.1.0 requests cairo-lang \ No newline at end of file diff --git a/scripts/deploy.py b/scripts/deploy.py index ce6b128..a801a7f 100644 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -1,6 +1,11 @@ # %% Imports import logging from asyncio import run +from dotenv import load_dotenv +import os + +load_dotenv() +NETWORK = os.getenv("STARKNET_NETWORK", "devnet") from utils.constants import COMPILED_CONTRACTS, ETH_TOKEN_ADDRESS from utils.starknet import ( @@ -14,6 +19,13 @@ logging.basicConfig() logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) +# https://api.starknet.id/uri?id= +MAINNET_CONST = [0x68747470733A2F2F6170692E737461726B6E65742E69642F7572693F69643D] +# https://goerli.api.starknet.id/uri?id=" +GOERLI_CONST = [ + 0x68747470733A2F2F676F65726C692E6170692E737461726B6E65742E69642F, + 0x7572693F69643D, +] # %% Main @@ -30,7 +42,7 @@ async def main(): deployments = {} deployments["identity_Identity"] = await deploy_v2( - "identity_Identity", + "identity_Identity", (MAINNET_CONST if NETWORK == "mainnet" else GOERLI_CONST) ) dump_deployments(deployments) diff --git a/scripts/utils/constants.py b/scripts/utils/constants.py index e56fda3..ff399a2 100644 --- a/scripts/utils/constants.py +++ b/scripts/utils/constants.py @@ -34,9 +34,7 @@ } VARS = NETWORKS[os.getenv("STARKNET_NETWORK", "devnet")] -VARS["account_address"] = os.environ.get( - f"{VARS['name'].upper()}_ACCOUNT_ADDRESS" -) +VARS["account_address"] = os.environ.get(f"{VARS['name'].upper()}_ACCOUNT_ADDRESS") if VARS["account_address"] is None: logger.warning( f"⚠️ {VARS['name'].upper()}_ACCOUNT_ADDRESS not set, defaulting to ACCOUNT_ADDRESS" @@ -63,7 +61,7 @@ ) ETH_TOKEN_ADDRESS = 0x49D36570D4E46F48E99674BD3FCC84644DDD6B96F7C741B1562B82F9E004DC7 -ETH_CLASS_HASH = 0x6a22bf63c7bc07effa39a25dfbd21523d211db0100a0afd054d172b81840eaf +ETH_CLASS_HASH = 0x6A22BF63C7BC07EFFA39A25DFBD21523D211DB0100A0AFD054D172B81840EAF SOURCE_DIR = Path("src") CONTRACTS = {p.stem: p for p in list(SOURCE_DIR.glob("**/*.cairo"))} diff --git a/scripts/utils/starknet.py b/scripts/utils/starknet.py index 77ef5fd..df74d6c 100644 --- a/scripts/utils/starknet.py +++ b/scripts/utils/starknet.py @@ -80,6 +80,7 @@ async def get_contract(contract_name) -> Contract: await get_starknet_account(), ) + def dump_declarations(declarations): json.dump( {name: hex(class_hash) for name, class_hash in declarations.items()}, @@ -127,21 +128,27 @@ def get_alias(contract_name): def get_tx_url(tx_hash: int) -> str: return f"{VARS['explorer_url']}/tx/0x{tx_hash:064x}" + def get_sierra_artifact(contract_name): - return BUILD_DIR / f"{contract_name}.sierra.json" + return BUILD_DIR / f"{contract_name}.contract_class.json" + def get_casm_artifact(contract_name): - return BUILD_DIR / f"{contract_name}.casm.json" + return BUILD_DIR / f"{contract_name}.compiled_contract_class.json" + def get_abi(contract_name): sierra_artifact = get_sierra_artifact(contract_name) contract_compiled_sierra = Path(sierra_artifact).read_text() - return create_sierra_compiled_contract(compiled_contract = contract_compiled_sierra).abi + return create_sierra_compiled_contract( + compiled_contract=contract_compiled_sierra + ).abi + async def declare_v2(contract_name): logger.info(f"ℹ️ Declaring {contract_name}") - # contract_compiled_casm is a string containing the content of the starknet-sierra-compile (.casm file) + # contract_compiled_casm is a string containing the content of the starknet-sierra-compile (.casm file) casm_artifact = get_casm_artifact(contract_name) contract_compiled_casm = Path(casm_artifact).read_text() casm_class = create_casm_class(contract_compiled_casm) @@ -151,11 +158,11 @@ async def declare_v2(contract_name): sierra_artifact = get_sierra_artifact(contract_name) contract_compiled_sierra = Path(sierra_artifact).read_text() sierra_class = create_sierra_compiled_contract(contract_compiled_sierra) - sierra_class_hash= compute_sierra_class_hash(sierra_class) + sierra_class_hash = compute_sierra_class_hash(sierra_class) # Check has not been declared before try: await GATEWAY_CLIENT.get_class_by_hash(class_hash=sierra_class_hash) - logger.info(f"✅ Class already declared, skipping") + logger.info(f"✅ Class {hex(sierra_class_hash)} already declared, skipping") return sierra_class_hash except Exception: pass @@ -175,6 +182,7 @@ async def declare_v2(contract_name): logger.info(f"✅ {contract_name} class hash: {hex(resp.class_hash)}") return resp.class_hash + async def deploy_v2(contract_name, *args): logger.info(f"ℹ️ Deploying {contract_name}") @@ -182,7 +190,7 @@ async def deploy_v2(contract_name, *args): sierra_class_hash = get_declarations()[contract_name] abi = get_abi(contract_name) - + deploy_result = await Contract.deploy_contract( account=account, class_hash=sierra_class_hash, @@ -208,11 +216,12 @@ async def invoke(contract_name, function_name, inputs, address=None): account = await get_starknet_account() deployments = get_deployments() call = Call( - to_addr=int(deployments[contract_name]["address"], 16) if address is None else address, - selector=get_selector_from_name(function_name), - calldata=inputs + to_addr=int(deployments[contract_name]["address"], 16) + if address is None + else address, + selector=get_selector_from_name(function_name), + calldata=inputs, ) - print("call", call) logger.info(f"ℹ️ Invoking {contract_name}.{function_name}({json.dumps(inputs)})") response = await account.execute(calls=call, max_fee=int(1e17)) await account.client.wait_for_tx(response.transaction_hash) @@ -222,6 +231,7 @@ async def invoke(contract_name, function_name, inputs, address=None): ) return response.transaction_hash + async def invoke_cairo0(contract_name, function_name, *inputs, address=None): account = await get_starknet_account() deployments = get_deployments() @@ -237,4 +247,4 @@ async def invoke_cairo0(contract_name, function_name, *inputs, address=None): f"✅ {contract_name}.{function_name} invoked at tx: %s", hex(response.transaction_hash), ) - return response.transaction_hash \ No newline at end of file + return response.transaction_hash diff --git a/src/identity.cairo b/src/identity.cairo index d18669a..1ba44d0 100644 --- a/src/identity.cairo +++ b/src/identity.cairo @@ -1 +1,3 @@ mod main; +mod internal; +mod erc721; \ No newline at end of file diff --git a/src/identity/erc721.cairo b/src/identity/erc721.cairo new file mode 100644 index 0000000..6aff887 --- /dev/null +++ b/src/identity/erc721.cairo @@ -0,0 +1,42 @@ +use openzeppelin::{ + token::erc721::{ERC721Component::{ERC721Metadata, HasComponent}}, + introspection::src5::SRC5Component, +}; +use custom_uri::{main::custom_uri_component::InternalImpl, main::custom_uri_component}; + + +#[starknet::interface] +trait IERC721Metadata { + fn name(self: @TState) -> felt252; + fn symbol(self: @TState) -> felt252; + fn token_uri(self: @TState, tokenId: u256) -> Array; + fn tokenURI(self: @TState, tokenId: u256) -> Array; +} + +#[starknet::embeddable] +impl IERC721MetadataImpl< + TContractState, + +HasComponent, + +SRC5Component::HasComponent, + +custom_uri_component::HasComponent, + +Drop +> of IERC721Metadata { + fn name(self: @TContractState) -> felt252 { + let component = HasComponent::get_component(self); + ERC721Metadata::name(component) + } + + fn symbol(self: @TContractState) -> felt252 { + let component = HasComponent::get_component(self); + ERC721Metadata::symbol(component) + } + + fn token_uri(self: @TContractState, tokenId: u256) -> Array { + let component = custom_uri_component::HasComponent::get_component(self); + component.get_uri(tokenId) + } + + fn tokenURI(self: @TContractState, tokenId: u256) -> Array { + self.token_uri(tokenId) + } +} diff --git a/src/identity/internal.cairo b/src/identity/internal.cairo new file mode 100644 index 0000000..9ada9c0 --- /dev/null +++ b/src/identity/internal.cairo @@ -0,0 +1,92 @@ +use identity::identity::main::Identity; +use starknet::{SyscallResultTrait, storage_base_address_from_felt252}; + +#[generate_trait] +impl InternalImpl of InternalTrait { + + fn get_extended( + self: @Identity::ContractState, + fn_name: felt252, + params: Span, + length: felt252, + domain: u32 + ) -> Span { + let base = self.compute_base_address(fn_name, params); + let mut data = ArrayTrait::new(); + let mut offset = 0; + loop { + if length == offset.into() { + break (); + } + let value = self._get(domain, storage_base_address_from_felt252(base + offset)); + data.append(value); + offset += 1; + }; + data.span() + } + + fn get_unbounded( + self: @Identity::ContractState, fn_name: felt252, params: Span, domain: u32 + ) -> Span { + let base = self.compute_base_address(fn_name, params); + let mut data = ArrayTrait::new(); + let mut offset = 0; + loop { + let value = self._get(domain, storage_base_address_from_felt252(base + offset)); + if value == 0 { + break (); + } + data.append(value); + offset += 1; + }; + data.span() + } + + fn _get( + self: @Identity::ContractState, domain: u32, base: starknet::StorageBaseAddress + ) -> felt252 { + starknet::storage_read_syscall( + domain, starknet::storage_address_from_base_and_offset(base, 0) + ) + .unwrap_syscall() + } + + fn set( + ref self: Identity::ContractState, + fn_name: felt252, + params: Span, + value: Span, + domain: u32, + ) { + let base = self.compute_base_address(fn_name, params); + self._set(domain, base, value); + } + + fn _set( + ref self: Identity::ContractState, domain: u32, base: felt252, mut values: Span, + ) { + match values.pop_back() { + Option::Some(value) => { + let addr = storage_base_address_from_felt252(base + values.len().into()); + starknet::storage_write_syscall( + domain, starknet::storage_address_from_base_and_offset(addr, 0), *value + ); + self._set(domain, base, values); + }, + Option::None(_) => {}, + } + } + + fn compute_base_address( + self: @Identity::ContractState, fn_name: felt252, mut params: Span + ) -> felt252 { + let mut hashed = fn_name; + loop { + match params.pop_front() { + Option::Some(param) => { hashed = hash::LegacyHash::hash(hashed, *param); }, + Option::None => { break; } + }; + }; + hashed + } +} diff --git a/src/identity/main.cairo b/src/identity/main.cairo index 6bf87f8..e0b1744 100644 --- a/src/identity/main.cairo +++ b/src/identity/main.cairo @@ -13,6 +13,15 @@ mod Identity { use core::pedersen; use storage_read::{main::storage_read_component, interface::IStorageRead}; use custom_uri::{interface::IInternalCustomURI, main::custom_uri_component}; + use openzeppelin::{ + account, access::ownable::OwnableComponent, + upgrades::{UpgradeableComponent, interface::IUpgradeable}, + token::erc721::{ + ERC721Component, erc721::ERC721Component::InternalTrait as ERC721InternalTrait + }, + introspection::{src5::SRC5Component, dual_src5::{DualCaseSRC5, DualCaseSRC5Trait}} + }; + use identity::identity::{internal::InternalTrait}; const USER_DATA_ADDR: felt252 = 1043580099640415304067929596039389735845630832049981224284932480360577081706; @@ -21,20 +30,56 @@ mod Identity { component!(path: custom_uri_component, storage: custom_uri, event: CustomUriEvent); component!(path: storage_read_component, storage: storage_read, event: StorageReadEvent); + component!(path: SRC5Component, storage: src5, event: SRC5Event); + component!(path: ERC721Component, storage: erc721, event: ERC721Event); + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent); + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent); + + // allow to check what interface is supported + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + #[abi(embed_v0)] + impl SRC5CamelImpl = SRC5Component::SRC5CamelImpl; + impl SRC5InternalImpl = SRC5Component::InternalImpl; + // make it a NFT + #[abi(embed_v0)] + impl ERC721Impl = ERC721Component::ERC721Impl; + #[abi(embed_v0)] + impl ERC721CamelOnlyImpl = ERC721Component::ERC721CamelOnlyImpl; + // allow to query name of nft collection #[abi(embed_v0)] - impl StorageReadComponent = storage_read_component::StorageRead; + impl IERC721MetadataImpl = + identity::identity::erc721::IERC721MetadataImpl; + // allow to query nft metadata json + #[abi(embed_v0)] + impl StorageReadImpl = storage_read_component::StorageRead; + // add an owner + #[abi(embed_v0)] + impl OwnableImpl = OwnableComponent::OwnableImpl; + impl OwnableInternalImpl = OwnableComponent::InternalImpl; + // make it upgradable + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl; #[storage] struct Storage { - owner_by_id: LegacyMap, user_data: LegacyMap<(u128, felt252), felt252>, verifier_data: LegacyMap<(u128, felt252, ContractAddress), felt252>, main_id_by_addr: LegacyMap, + // legacy owner + Proxy_admin: felt252, #[substorage(v0)] custom_uri: custom_uri_component::Storage, #[substorage(v0)] storage_read: storage_read_component::Storage, + #[substorage(v0)] + src5: SRC5Component::Storage, + #[substorage(v0)] + erc721: ERC721Component::Storage, + #[substorage(v0)] + ownable: OwnableComponent::Storage, + #[substorage(v0)] + upgradeable: UpgradeableComponent::Storage } // @@ -48,8 +93,13 @@ mod Identity { ExtendedVerifierDataUpdate: ExtendedVerifierDataUpdate, UserDataUpdate: UserDataUpdate, ExtendedUserDataUpdate: ExtendedUserDataUpdate, + // components CustomUriEvent: custom_uri_component::Event, - StorageReadEvent: storage_read_component::Event + StorageReadEvent: storage_read_component::Event, + SRC5Event: SRC5Component::Event, + ERC721Event: ERC721Component::Event, + OwnableEvent: OwnableComponent::Event, + UpgradeableEvent: UpgradeableComponent::Event } #[derive(Drop, starknet::Event)] @@ -87,19 +137,26 @@ mod Identity { } #[constructor] - fn constructor(ref self: ContractState, token_uri_base: Span,) { + fn constructor( + ref self: ContractState, owner: ContractAddress, token_uri_base: Span, + ) { + self.ownable.initializer(owner); + self.erc721.initializer('Starknet.id', 'ID'); self.custom_uri.set_base_uri(token_uri_base); } #[external(v0)] - impl IdentityImpl of IIdentity { - fn tokenURI(self: @ContractState, tokenId: u256) -> Array { - self.custom_uri.get_uri(tokenId) + impl UpgradeableImpl of IUpgradeable { + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) { + self.ownable.assert_only_owner(); + self.upgradeable._upgrade(new_class_hash); } + } - fn owner_of(self: @ContractState, id: u128) -> ContractAddress { - // todo: when components are ready, use ERC721 - self.owner_by_id.read(id) + #[external(v0)] + impl IdentityImpl of IIdentity { + fn owner_from_id(self: @ContractState, id: u128) -> ContractAddress { + self.erc721._owner_of(u256 { low: id, high: 0 }) } fn get_main_id(self: @ContractState, user: ContractAddress) -> u128 { @@ -173,16 +230,13 @@ mod Identity { } fn mint(ref self: ContractState, id: u128) { - // todo: when components are ready, use ERC721 - if self.owner_by_id.read(id).into() == 0 { - self.owner_by_id.write(id, get_caller_address()); - } + self.erc721._mint(get_caller_address(), id.into()); } fn set_main_id(ref self: ContractState, id: u128) { // todo: add event let caller = get_caller_address(); - assert(caller == self.owner_by_id.read(id), 'you don\'t own this id'); + assert(caller == self.erc721._owner_of(id.into()), 'you don\'t own this id'); self.main_id_by_addr.write(caller, id); } @@ -203,7 +257,7 @@ mod Identity { ref self: ContractState, id: u128, field: felt252, data: Span, domain: u32 ) { let caller = get_caller_address(); - assert(caller == self.owner_by_id.read(id), 'you don\'t own this id'); + assert(caller == self.erc721._owner_of(id.into()), 'you don\'t own this id'); self.set(USER_DATA_ADDR, array![id.into(), field].span(), data, domain); self .emit( @@ -245,95 +299,13 @@ mod Identity { ) ); } - } - // - // Internals - // - - #[generate_trait] - impl InternalImpl of InternalTrait { - // todo: move these functions into a storage contract when components are available - fn get_extended( - self: @ContractState, - fn_name: felt252, - params: Span, - length: felt252, - domain: u32 - ) -> Span { - let base = self.compute_base_address(fn_name, params); - let mut data = ArrayTrait::new(); - let mut offset = 0; - loop { - if length == offset.into() { - break (); - } - let value = self._get(domain, storage_base_address_from_felt252(base + offset)); - data.append(value); - offset += 1; - }; - data.span() - } - - fn get_unbounded( - self: @ContractState, fn_name: felt252, params: Span, domain: u32 - ) -> Span { - let base = self.compute_base_address(fn_name, params); - let mut data = ArrayTrait::new(); - let mut offset = 0; - loop { - let value = self._get(domain, storage_base_address_from_felt252(base + offset)); - if value == 0 { - break (); - } - data.append(value); - offset += 1; - }; - data.span() - } - - fn _get(self: @ContractState, domain: u32, base: starknet::StorageBaseAddress) -> felt252 { - starknet::storage_read_syscall( - domain, starknet::storage_address_from_base_and_offset(base, 0) - ) - .unwrap_syscall() - } - - fn set( - ref self: ContractState, - fn_name: felt252, - params: Span, - value: Span, - domain: u32, - ) { - let base = self.compute_base_address(fn_name, params); - self._set(domain, base, value); - } - - fn _set(ref self: ContractState, domain: u32, base: felt252, mut values: Span,) { - match values.pop_back() { - Option::Some(value) => { - let addr = storage_base_address_from_felt252(base + values.len().into()); - starknet::storage_write_syscall( - domain, starknet::storage_address_from_base_and_offset(addr, 0), *value - ); - self._set(domain, base, values); - }, - Option::None(_) => {}, - } - } - - fn compute_base_address( - self: @ContractState, fn_name: felt252, mut params: Span - ) -> felt252 { - let mut hashed = fn_name; - loop { - match params.pop_front() { - Option::Some(param) => { hashed = hash::LegacyHash::hash(hashed, *param); }, - Option::None => { break; } - }; - }; - hashed + // this function should be called after upgrading from Cairo 0 contract + fn finalize_migration(ref self: ContractState, token_uri_base: Span) { + let caller = get_caller_address(); + assert(caller.into() == self.Proxy_admin.read(), 'only proxy admin can migrate'); + self.ownable.initializer(caller); + self.custom_uri.set_base_uri(token_uri_base); } } } diff --git a/src/interface/identity.cairo b/src/interface/identity.cairo index efcc4f1..7a17559 100644 --- a/src/interface/identity.cairo +++ b/src/interface/identity.cairo @@ -2,9 +2,7 @@ use starknet::ContractAddress; #[starknet::interface] trait IIdentity { - fn tokenURI(self: @TContractState, tokenId: u256) -> Array; - - fn owner_of(self: @TContractState, id: u128) -> ContractAddress; + fn owner_from_id(self: @TContractState, id: u128) -> ContractAddress; fn get_user_data(self: @TContractState, id: u128, field: felt252, domain: u32) -> felt252; @@ -47,8 +45,6 @@ trait IIdentity { fn reset_main_id(ref self: TContractState); - // todo: add support for multifelts data - fn set_user_data( ref self: TContractState, id: u128, field: felt252, data: felt252, domain: u32 ); @@ -64,4 +60,6 @@ trait IIdentity { fn set_extended_verifier_data( ref self: TContractState, id: u128, field: felt252, data: Span, domain: u32 ); + + fn finalize_migration(ref self: TContractState, token_uri_base: Span); } diff --git a/src/tests/test_addresses_comp.cairo b/src/tests/test_addresses_comp.cairo index 62ff7a6..c64ab48 100644 --- a/src/tests/test_addresses_comp.cairo +++ b/src/tests/test_addresses_comp.cairo @@ -1,6 +1,7 @@ use starknet::testing; -use identity::identity::main::Identity; +use identity::identity::internal::InternalImpl; use identity::interface::identity::{IIdentity, IIdentityDispatcher, IIdentityDispatcherTrait}; +use identity::identity::main::Identity; use debug::PrintTrait; use starknet::{SyscallResultTrait, StorageBaseAddress}; use traits::{Into, TryInto}; @@ -15,14 +16,14 @@ fn test_compute_address_single_param() { // It should return the same value as utils::get_storage_var_address() from starknet-rs let expected_0 = 0x04496ba66d9685813220a5ba3d7b2be924385ad47abfafeec804b0e2f3f0ec56; - let computed_addr_0 = Identity::InternalImpl::compute_base_address( + let computed_addr_0 = InternalImpl::compute_base_address( @unsafe_state, VERIFIER_DATA_ADDR, array![0].span() ); assert(computed_addr_0 == expected_0, 'Invalid storage address'); // It should return the same value as utils::get_storage_var_address() from starknet-rs let expected: felt252 = 0x01f65ea3e42f099a1c085eecf45ce0d476a1ab440e3ed539604cac5ba6944258; - let computed_addr = Identity::InternalImpl::compute_base_address( + let computed_addr = InternalImpl::compute_base_address( @unsafe_state, VERIFIER_DATA_ADDR, array![123].span() ); assert(computed_addr == expected, 'Invalid storage address'); @@ -36,7 +37,7 @@ fn test_compute_address_multiple_params() { // It should return the same value as utils::get_storage_var_address() from starknet-rs let expected = 0x023289a31298cac4a750e1fbc154c96b5398aa7e94018d9d5c115690aa124767; - let computed_addr = Identity::InternalImpl::compute_base_address( + let computed_addr = InternalImpl::compute_base_address( @unsafe_state, VERIFIER_DATA_ADDR, array![0, 1, 3].span() ); assert(computed_addr == expected, 'Invalid storage address'); @@ -50,7 +51,7 @@ fn test_compute_address_empty_param() { // It should return the same value as utils::get_storage_var_address() from starknet-rs let expected = 0x00ac8e2e1fdb949863544c38e1ed04b4c447121f2b60005f7c7f798c6a35ab40; - let computed_addr = Identity::InternalImpl::compute_base_address( + let computed_addr = InternalImpl::compute_base_address( @unsafe_state, VERIFIER_DATA_ADDR, array![].span() ); assert(computed_addr == expected, 'Invalid storage address'); diff --git a/src/tests/test_extended_data.cairo b/src/tests/test_extended_data.cairo index 4238b8a..42e992a 100644 --- a/src/tests/test_extended_data.cairo +++ b/src/tests/test_extended_data.cairo @@ -4,19 +4,15 @@ use zeroable::Zeroable; use traits::Into; use starknet::{ContractAddress, contract_address_const}; use starknet::testing::set_contract_address; -use super::utils; +use super::utils::deploy_identity; use identity::interface::identity::{IIdentityDispatcher, IIdentityDispatcherTrait}; use identity::identity::main::Identity; -fn deploy_identity() -> IIdentityDispatcher { - let address = utils::deploy(Identity::TEST_CLASS_HASH, array![0]); - IIdentityDispatcher { contract_address: address } -} - #[test] #[available_gas(20000000000)] fn test_verifier_data() { let identity = deploy_identity(); + set_contract_address(contract_address_const::<0x456>()); identity.mint(1); let caller = contract_address_const::<0x456>(); set_contract_address(caller); @@ -28,6 +24,7 @@ fn test_verifier_data() { #[available_gas(20000000000)] fn test_extended_verifier_data() { let identity = deploy_identity(); + set_contract_address(contract_address_const::<0x156763>()); identity.mint(1); let caller = contract_address_const::<0x456>(); set_contract_address(caller); @@ -45,6 +42,7 @@ fn test_extended_verifier_data() { fn test_get_extended_verifier_data_len_1() { // It should test that data written with set_verifier_data is correctly fetched with get_extended_user_data let identity = deploy_identity(); + set_contract_address(contract_address_const::<0x456>()); identity.mint(1); let caller = contract_address_const::<0x456>(); set_contract_address(caller); @@ -61,6 +59,7 @@ fn test_set_extended_verifier_data_len_1() { // It should test that writing extended verifier data of length 1 // fetching with get_verifier_data returns the correct value let identity = deploy_identity(); + set_contract_address(contract_address_const::<0x456>()); identity.mint(1); let caller = contract_address_const::<0x456>(); set_contract_address(caller); @@ -72,6 +71,7 @@ fn test_set_extended_verifier_data_len_1() { #[available_gas(20000000000)] fn test_unbounded_verifier_data() { let identity = deploy_identity(); + set_contract_address(contract_address_const::<0x456>()); identity.mint(1); let caller = contract_address_const::<0x456>(); set_contract_address(caller); @@ -117,6 +117,7 @@ fn test_unbounded_user_data() { #[should_panic(expected: ('you don\'t own this id', 'ENTRYPOINT_FAILED'))] fn test_set_user_data_not_owner() { let identity = deploy_identity(); + set_contract_address(contract_address_const::<0x789>()); identity.mint(1); let caller = contract_address_const::<0x456>(); set_contract_address(caller); diff --git a/src/tests/test_identity.cairo b/src/tests/test_identity.cairo index 3d68a51..f91251b 100644 --- a/src/tests/test_identity.cairo +++ b/src/tests/test_identity.cairo @@ -4,19 +4,16 @@ use zeroable::Zeroable; use traits::Into; use starknet::{ContractAddress, contract_address_const}; use starknet::testing::set_contract_address; -use super::utils; +use super::utils::deploy_identity; use identity::interface::identity::{IIdentityDispatcher, IIdentityDispatcherTrait}; use identity::identity::main::Identity; -fn deploy_identity() -> IIdentityDispatcher { - let address = utils::deploy(Identity::TEST_CLASS_HASH, array![0]); - IIdentityDispatcher { contract_address: address } -} #[test] #[available_gas(20000000000)] fn test_user_data() { let identity = deploy_identity(); + set_contract_address(contract_address_const::<0x456>()); identity.mint(1); identity.set_user_data(1, 'starknet', 0x123, 0); @@ -27,6 +24,7 @@ fn test_user_data() { #[available_gas(20000000000)] fn test_verifier_data() { let identity = deploy_identity(); + set_contract_address(contract_address_const::<0x456>()); identity.mint(1); let caller = contract_address_const::<0x456>(); set_contract_address(caller); diff --git a/src/tests/utils.cairo b/src/tests/utils.cairo index 4c518dd..eaecf27 100644 --- a/src/tests/utils.cairo +++ b/src/tests/utils.cairo @@ -2,8 +2,12 @@ use array::ArrayTrait; use core::result::ResultTrait; use option::OptionTrait; use starknet::{class_hash::Felt252TryIntoClassHash, ContractAddress, SyscallResultTrait}; +use identity::interface::identity::{IIdentityDispatcher, IIdentityDispatcherTrait}; +use identity::identity::main::Identity; use traits::TryInto; +const ADMIN: felt252 = 0x123; + fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAddress { let (address, _) = starknet::deploy_syscall( contract_class_hash.try_into().unwrap(), 0, calldata.span(), false @@ -11,3 +15,8 @@ fn deploy(contract_class_hash: felt252, calldata: Array) -> ContractAdd .unwrap_syscall(); address } + +fn deploy_identity() -> IIdentityDispatcher { + let address = deploy(Identity::TEST_CLASS_HASH, array![ADMIN, 0]); + IIdentityDispatcher { contract_address: address } +}