diff --git a/README.md b/README.md index 33146de..bbb51cd 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ StarkNet is still in Alpha. This means that development is ongoing, and the pain The goal of this tutorial is for you to customize and deploy an ERC721 contract on StarkNet. Your progress will be check by an [evaluator contract](contracts/Evaluator.cairo), deployed on StarkNet, which will grant you points in the form of [ERC20 tokens](contracts/token/ERC20/TDERC20.cairo). -Each exercice will require you to add functionnality to your ERC721 token. +Each exercise will require you to add functionnality to your ERC721 token. -For each exercice, you will have to write a new version on your contract, deploy it, and submit it to the evaluator for correction. +For each exercise, you will have to write a new version on your contract, deploy it, and submit it to the evaluator for correction. ### Where am I? @@ -143,7 +143,7 @@ For example to solve the first exercise the workflow would be the following: - The 'transfer' function of ERC721-101 has been disabled to encourage you to finish the tutorial with only one address - In order to receive points, the evaluator has to reach the calls to the `distribute_point` function. -- This repo contains an interface `IExerciceSolution.cairo`. Your ERC721 contract will have to conform to this interface in order to validate some exercises; that is, your contract needs to implement all the functions described in `IExerciceSolution.cairo`. +- This repo contains an interface `IExerciseSolution.cairo`. Your ERC721 contract will have to conform to this interface in order to validate some exercises; that is, your contract needs to implement all the functions described in `IExerciseSolution.cairo`. - **We really recommend that your read the [`Evaluator.cairo`](contracts/Evaluator.cairo) contract in order to fully understand what's expected for each exercise**. A high level description of what is expected for each exercise is provided in this readme. - The Evaluator contract sometimes needs to make payments to buy your tokens. Make sure he has enough dummy tokens to do so! If not, you should get dummy tokens from the dummy tokens contract and send them to the evaluator @@ -181,7 +181,7 @@ starknet deploy --contract artifacts/ERC721.json --inputs arg1 arg2 arg3 --netwo - Call [`ex2a_get_animal_rank()`](contracts/Evaluator.cairo#L245) to get assigned a random creature to create. - Read the expected characteristics of your animal from the Evaluator -- Create the tools necessary to record animals characteristics in your contract and enable the evaluator contract to retrieve them trough `get_animal_characteristics` function on your contract ([check this](contracts/IExerciceSolution.cairo)) +- Create the tools necessary to record animals characteristics in your contract and enable the evaluator contract to retrieve them trough `get_animal_characteristics` function on your contract ([check this](contracts/IExerciseSolution.cairo)) - Deploy your new contract - Mint the animal with the desired characteristics and give it to the evaluator - Call [`submit_exercise()`](contracts/Evaluator.cairo#L601) in the Evaluator to configure the contract you want evaluated @@ -206,7 +206,7 @@ starknet deploy --contract artifacts/ERC721.json --inputs arg1 arg2 arg3 --netwo - Use [dummy token faucet](contracts/token/ERC20/dummy_token.cairo) to get dummy tokens - Use [`ex5a_i_have_dtk()`](contracts/Evaluator.cairo#L406) to show you managed to use the faucet (2 pts) - Create a function to allow breeder registration. -- This function should charge the registrant for a fee, paid in dummy tokens ([check `registration_price`](contracts/IExerciceSolution.cairo)) +- This function should charge the registrant for a fee, paid in dummy tokens ([check `registration_price`](contracts/IExerciseSolution.cairo)) - Add permissions. Only allow listed breeders should be able to create animals - Deploy your new contract - Call [`submit_exercise()`](contracts/Evaluator.cairo#L601) in the Evaluator to configure the contract you want evaluated diff --git a/contracts/Evaluator.cairo b/contracts/Evaluator.cairo index c536eba..83f230f 100644 --- a/contracts/Evaluator.cairo +++ b/contracts/Evaluator.cairo @@ -11,12 +11,12 @@ from contracts.utils.ex00_base import ( distribute_points, ex_initializer, has_validated_exercise, - validate_exercice, + validate_exercise, ) from contracts.token.ERC721.IERC721 import IERC721 from contracts.token.ERC721.IERC721_metadata import IERC721_metadata -from contracts.IExerciceSolution import IExerciceSolution +from contracts.IExerciseSolution import IExerciseSolution from starkware.starknet.common.syscalls import get_contract_address, get_caller_address from starkware.cairo.common.uint256 import ( Uint256, @@ -231,7 +231,7 @@ func ex1_test_erc721{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_che if has_validated == 0: # player has validated - validate_exercice(sender_address, 1) + validate_exercise(sender_address, 1) # Sending points distribute_points(sender_address, 2) return () @@ -291,7 +291,7 @@ func ex3_declare_new_animal{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, ra with_attr error_message("Couldn't declare a new animal"): # Declaring a new animal with the desired parameters - let (created_token) = IExerciceSolution.declare_animal( + let (created_token) = IExerciseSolution.declare_animal( contract_address=submited_exercise_address, sex=expected_sex, legs=expected_legs, @@ -309,7 +309,7 @@ func ex3_declare_new_animal{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, ra if has_validated == 0: # player has validated - validate_exercice(sender_address, 3) + validate_exercise(sender_address, 3) # Sending points distribute_points(sender_address, 2) return () @@ -335,14 +335,14 @@ func ex4_declare_dead_animal{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, r # Getting an animal id of Evaluator. tokenOfOwnerByIndex should return the list of NFTs owned by and address with_attr error_message("Can't get the token owner by the index"): - let (token_id) = IExerciceSolution.token_of_owner_by_index( + let (token_id) = IExerciseSolution.token_of_owner_by_index( contract_address=submited_exercise_address, account=evaluator_address, index=0 ) end with_attr error_message("Can't declare a dead animal"): # Declaring it as dead - IExerciceSolution.declare_dead_animal( + IExerciseSolution.declare_dead_animal( contract_address=submited_exercise_address, token_id=token_id ) end @@ -367,7 +367,7 @@ func ex4_declare_dead_animal{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, r with_attr error_message("Couldn't get the animal's characteristics"): # Check that properties are deleted # Reading animal characteristic in player solution - let (read_sex, read_legs, read_wings) = IExerciceSolution.get_animal_characteristics( + let (read_sex, read_legs, read_wings) = IExerciseSolution.get_animal_characteristics( contract_address=submited_exercise_address, token_id=token_id ) end @@ -392,7 +392,7 @@ func ex4_declare_dead_animal{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, r if has_validated == 0: # player has validated - validate_exercice(sender_address, 4) + validate_exercise(sender_address, 4) # Sending points distribute_points(sender_address, 2) return () @@ -426,7 +426,7 @@ func ex5a_i_have_dtk{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_che if has_validated == 0: # player has validated - validate_exercice(sender_address, 51) + validate_exercise(sender_address, 51) # Sending points distribute_points(sender_address, 2) return () @@ -446,7 +446,7 @@ func ex5b_register_breeder{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, ran # Get evaluator address let (evaluator_address) = get_contract_address() # Is evaluator currently a breeder? - let (is_evaluator_breeder_init) = IExerciceSolution.is_breeder( + let (is_evaluator_breeder_init) = IExerciseSolution.is_breeder( contract_address=submited_exercise_address, account=evaluator_address ) with_attr error_message("Evaluator shouldn't be a breeder for now"): @@ -456,7 +456,7 @@ func ex5b_register_breeder{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, ran # Reading registration price. Registration is payable in dummy token with_attr error_message("Couldn't read the registration price"): - let (registration_price) = IExerciceSolution.registration_price( + let (registration_price) = IExerciseSolution.registration_price( contract_address=submited_exercise_address ) end @@ -466,7 +466,7 @@ func ex5b_register_breeder{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, ran let (dummy_token_init_balance) = IERC20.balanceOf( contract_address=dummy_token_address, account=evaluator_address ) - # Approve the exercice for spending my dummy tokens + # Approve the exercise for spending my dummy tokens IERC20.approve( contract_address=dummy_token_address, spender=submited_exercise_address, @@ -475,12 +475,12 @@ func ex5b_register_breeder{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, ran # Require breeder permission. with_attr error_message("Couldn't register the Evaluator as a breeder"): - IExerciceSolution.register_me_as_breeder(contract_address=submited_exercise_address) + IExerciseSolution.register_me_as_breeder(contract_address=submited_exercise_address) end with_attr error_message("Couldn't check that the evaluator is a breeder"): # Check that I am indeed a breeder - let (is_evaluator_breeder_end) = IExerciceSolution.is_breeder( + let (is_evaluator_breeder_end) = IExerciseSolution.is_breeder( contract_address=submited_exercise_address, account=evaluator_address ) end @@ -510,7 +510,7 @@ func ex5b_register_breeder{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, ran if has_validated == 0: # player has validated - validate_exercice(sender_address, 52) + validate_exercise(sender_address, 52) # Sending points distribute_points(sender_address, 2) return () @@ -545,7 +545,7 @@ func ex6_claim_metadata_token{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, if has_validated == 0: # player has validated - validate_exercice(sender_address, 6) + validate_exercise(sender_address, 6) # Sending points distribute_points(sender_address, 2) return () @@ -590,7 +590,7 @@ func ex7_add_metadata{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_ch if has_validated == 0: # player has validated - validate_exercice(sender_address, 7) + validate_exercise(sender_address, 7) # Sending points distribute_points(sender_address, 2) return () @@ -621,7 +621,7 @@ func submit_exercise{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_che if has_validated == 0: # player has validated - validate_exercice(sender_address, 0) + validate_exercise(sender_address, 0) # Sending points # Deploying contract points @@ -683,7 +683,7 @@ func ex2b_test_declare_animal_internal{ with_attr error_message("Couldn't retrieve the animal's characteristics"): # Reading animal characteristic in player solution - let (read_sex, read_legs, read_wings) = IExerciceSolution.get_animal_characteristics( + let (read_sex, read_legs, read_wings) = IExerciseSolution.get_animal_characteristics( contract_address=submited_exercise_address, token_id=token_id ) end @@ -704,7 +704,7 @@ func ex2b_test_declare_animal_internal{ if has_validated == 0: # player has validated - validate_exercice(sender_address, 2) + validate_exercise(sender_address, 2) # Sending points distribute_points(sender_address, 2) return () @@ -727,7 +727,7 @@ func ex7_check_arrays_are_equal{syscall_ptr : felt*, pedersen_ptr : HashBuiltin* end # # External functions - Administration -# Only admins can call these. You don't need to understand them to finish the exercice. +# Only admins can call these. You don't need to understand them to finish the exercise. # @external diff --git a/contracts/IExerciceSolution.cairo b/contracts/IExerciseSolution.cairo similarity index 95% rename from contracts/IExerciceSolution.cairo rename to contracts/IExerciseSolution.cairo index e34369c..92e2aac 100644 --- a/contracts/IExerciceSolution.cairo +++ b/contracts/IExerciseSolution.cairo @@ -3,7 +3,7 @@ from starkware.cairo.common.uint256 import Uint256 @contract_interface -namespace IExerciceSolution: +namespace IExerciseSolution: # Breeding function func is_breeder(account : felt) -> (is_approved : felt): end diff --git a/contracts/token/ERC20/TDERC20.cairo b/contracts/token/ERC20/TDERC20.cairo index df85a23..5d0a428 100644 --- a/contracts/token/ERC20/TDERC20.cairo +++ b/contracts/token/ERC20/TDERC20.cairo @@ -149,7 +149,7 @@ end func distribute_points{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}( to : felt, amount : Uint256 ): - only_teacher_or_exercice() + only_teacher_or_exercise() ERC20_mint(to, amount) return () end @@ -158,7 +158,7 @@ end func remove_points{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}( to : felt, amount : Uint256 ): - only_teacher_or_exercice() + only_teacher_or_exercise() ERC20_burn(to, amount) return () end @@ -167,7 +167,7 @@ end func set_teacher{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}( account : felt, permission : felt ): - only_teacher_or_exercice() + only_teacher_or_exercise() teachers_and_exercises_accounts.write(account, permission) return () @@ -177,7 +177,7 @@ end func set_teachers{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}( accounts_len : felt, accounts : felt* ): - only_teacher_or_exercice() + only_teacher_or_exercise() _set_teacher(accounts_len, accounts) return () end @@ -186,7 +186,7 @@ end func set_transferable{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}( permission : felt ): - only_teacher_or_exercice() + only_teacher_or_exercise() _set_transferable(permission) return () end @@ -215,7 +215,7 @@ func _set_teacher{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ return () end -func only_teacher_or_exercice{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(): +func only_teacher_or_exercise{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(): let (caller) = get_caller_address() let (permission) = teachers_and_exercises_accounts.read(account=caller) assert permission = 1 diff --git a/contracts/utils/Iplayers_registry.cairo b/contracts/utils/Iplayers_registry.cairo index 8fee31e..3dff3bb 100644 --- a/contracts/utils/Iplayers_registry.cairo +++ b/contracts/utils/Iplayers_registry.cairo @@ -6,8 +6,8 @@ @contract_interface namespace Iplayers_registry: - func has_validated_exercice(account : felt, workshop : felt, exercise : felt) -> ( - has_validated_exercice : felt + func has_validated_exercise(account : felt, workshop : felt, exercise : felt) -> ( + has_validated_exercise : felt ): end func is_exercise_or_admin(account : felt) -> (permission : felt): @@ -22,6 +22,6 @@ namespace Iplayers_registry: end func set_exercises_or_admins(accounts_len : felt, accounts : felt*): end - func validate_exercice(account : felt, workshop : felt, exercise : felt): + func validate_exercise(account : felt, workshop : felt, exercise : felt): end end diff --git a/contracts/utils/ex00_base.cairo b/contracts/utils/ex00_base.cairo index 1a3bf82..df98941 100644 --- a/contracts/utils/ex00_base.cairo +++ b/contracts/utils/ex00_base.cairo @@ -61,18 +61,18 @@ end @view func has_validated_exercise{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}( account : felt, exercise_id : felt -) -> (has_validated_exercice : felt): +) -> (has_validated_exercise : felt): # reading player registry let (_players_registry) = players_registry_storage.read() let (_workshop_id) = workshop_id_storage.read() - # Checking if the user already validated this exercice - let (has_current_user_validated_exercice) = Iplayers_registry.has_validated_exercice( + # Checking if the user already validated this exercise + let (has_current_user_validated_exercise) = Iplayers_registry.has_validated_exercise( contract_address=_players_registry, account=account, workshop=_workshop_id, exercise=exercise_id, ) - return (has_current_user_validated_exercice) + return (has_current_user_validated_exercise) end # @@ -108,23 +108,23 @@ func distribute_points{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_c return () end -func validate_exercice{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}( +func validate_exercise{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}( account : felt, exercise_id ): # reading player registry let (_players_registry) = players_registry_storage.read() let (_workshop_id) = workshop_id_storage.read() - # Checking if the user already validated this exercice - let (has_current_user_validated_exercice) = Iplayers_registry.has_validated_exercice( + # Checking if the user already validated this exercise + let (has_current_user_validated_exercise) = Iplayers_registry.has_validated_exercise( contract_address=_players_registry, account=account, workshop=_workshop_id, exercise=exercise_id, ) - assert (has_current_user_validated_exercice) = 0 + assert (has_current_user_validated_exercise) = 0 - # Marking the exercice as completed - Iplayers_registry.validate_exercice( + # Marking the exercise as completed + Iplayers_registry.validate_exercise( contract_address=_players_registry, account=account, workshop=_workshop_id, diff --git a/contracts/utils/players_registry.cairo b/contracts/utils/players_registry.cairo index 910747a..55bcdec 100644 --- a/contracts/utils/players_registry.cairo +++ b/contracts/utils/players_registry.cairo @@ -20,8 +20,8 @@ from starkware.starknet.common.syscalls import get_caller_address # @storage_var -func has_validated_exercice_storage(account : felt, workshop : felt, exercise : felt) -> ( - has_validated_exercice_storage : felt +func has_validated_exercise_storage(account : felt, workshop : felt, exercise : felt) -> ( + has_validated_exercise_storage : felt ): end @@ -47,11 +47,11 @@ end # @view -func has_validated_exercice{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}( +func has_validated_exercise{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}( account : felt, workshop : felt, exercise : felt -) -> (has_validated_exercice : felt): - let (has_validated_exercice) = has_validated_exercice_storage.read(account, workshop, exercise) - return (has_validated_exercice) +) -> (has_validated_exercise : felt): + let (has_validated_exercise) = has_validated_exercise_storage.read(account, workshop, exercise) + return (has_validated_exercise) end @view @@ -175,18 +175,18 @@ func set_exercises_or_admins{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, r end @external -func validate_exercice{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}( +func validate_exercise{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}( account : felt, workshop : felt, exercise : felt ): only_exercise_or_admin() - # Checking if the user already validated this exercice - let (has_current_user_validated_exercice) = has_validated_exercice_storage.read( + # Checking if the user already validated this exercise + let (has_current_user_validated_exercise) = has_validated_exercise_storage.read( account, workshop, exercise ) - assert (has_current_user_validated_exercice) = 0 + assert (has_current_user_validated_exercise) = 0 - # Marking the exercice as completed - has_validated_exercice_storage.write(account, workshop, exercise, 1) + # Marking the exercise as completed + has_validated_exercise_storage.write(account, workshop, exercise, 1) new_validation.emit(account=account, workshop=workshop, exercise=exercise) # Recording player if he is not yet recorded