diff --git a/cairo.html.markdown b/cairo.html.markdown index 95008a78..e6a04b67 100644 --- a/cairo.html.markdown +++ b/cairo.html.markdown @@ -180,7 +180,7 @@ func increase_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, let (res) = balance.read(); balance.write(res + amount); return (); - } +} // @dev returns the balance variable // @view is a decorator that specifies the func below it is a view function. @@ -189,7 +189,7 @@ func get_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (res: felt) { let (res) = balance.read(); return (res,); - } +} ``` Before proceeding to the main lessons, try to build, deploy and interact with @@ -204,10 +204,10 @@ just a single data type `..felts`. Felts stands for Field elements, and are a create a `Uint256` in Cairo by utlizing a struct of two 128 bits felts. ```cairo -struct Uint256{ +struct Uint256 { low: felt, // The low 128 bits of the value. high: felt, // The high 128 bits of the value. - } +} ``` To avoid running into issues with divisions, it's safer to work with the @@ -239,19 +239,19 @@ from starkware.cairo.common.bool import TRUE + Storage variables: Cairo's storage is a map with `2^251` slots, where each slot is a felt which is initialized to `0`. You create one using the - `@storage_var` decorator + `@storage_var` decorator. ```cairo @storage_var - func names() -> (name: felt){} + func names() -> (name: felt) {} ``` -+ Storage mappings: Unlike soldity where mappings have a separate keyword, in ++ Storage mappings: Unlike Solidity where mappings have a separate keyword, in Cairo you create mappings using storage variables. ```cairo @storage_var - func names(address: felt) -> (name: felt){} + func names(address: felt) -> (name: felt) {} ``` + Structs: are a means to create custom data types in Cairo. A `struct` has a @@ -269,7 +269,7 @@ from starkware.cairo.common.bool import TRUE + Constants: Constants are fixed and as such can't be altered after being set. They evaluate to an integer (field element) at compile time. To create a - constant in Cairo, you use the `const` keyword. Its proper practice to + constant in Cairo, you use the `const` keyword. It's proper practice to capitalize constant names. ```cairo @@ -423,11 +423,11 @@ Here are the most common decorators you'll encounter in Cairo: ```cairo func store_name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, - range_check_ptr}(_name: felt){ - let (caller) = get_caller_address(); - names.write(caller, _name); - stored_name.emit(caller, _name); - return (); + range_check_ptr}(_name: felt){ + let (caller) = get_caller_address(); + names.write(caller, _name); + stored_name.emit(caller, _name); + return (); } ``` @@ -479,12 +479,12 @@ contract passing in the contract address as the first parameter like this: IENS.store_name(contract_address, _name); ``` -Note that Interfaces excludes the function body/logic and the implicit +Note that Interfaces exclude the function body/logic and the implicit arguments. ### 9. Recursions -Due to the unavailability of loops, Recursions are the go-to for similar +Due to the unavailability of loops, Recursion is the go-to for similar operations. In simple terms, a recursive function is one which calls itself repeatedly. @@ -494,25 +494,25 @@ fibonacci number: ```cairo @external func fibonacci{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, - range_check_ptr}(n : felt) -> (result : felt){ - alloc_locals; - if (n == 0){ - return (0); - } - if (n == 1){ - return (1); - } - let (local x) = fibonacci(n - 1); - let (local y) = fibonacci(n - 2); - return (result=(x + y)); +range_check_ptr}(n : felt) -> (result : felt){ + alloc_locals; + if (n == 0){ + return (0); } + if (n == 1){ + return (1); + } + let (local x) = fibonacci(n - 1); + let (local y) = fibonacci(n - 2); + return (result=(x + y)); +} ``` The nth fibonacci term is the sum of the `nth - 1` and the `nth - 2` numbers, that's why we get these two as `(x,y)` using recursion. NB: when implementing recursive functions, always remember to implement a base -case (`n==0`, `n==1` in our case), to prevent stack overflow. +case (`n==0`, `n==1` in our case), to prevent stack overflows. ### 10. Registers @@ -529,8 +529,8 @@ registers: ### 11. Revoked References -Revoked references occurs when there is a call instruction to another function, -between the definition of a reference variable that depends on `ap`(temp +Revoked references occur when there is a call instruction to another function, +between the definition of a reference variable that depends on `ap` (temp variables) and its usage. This occurs as the compiler may not be able to compute the change of `ap` (as one may jump to the label from another place in the program, or call a function that might change ap in an unknown way). @@ -540,18 +540,18 @@ Here is an example to demonstrate what I mean: ```cairo @external func get_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, - range_check_ptr}() -> (res: felt) { - return (res=100); - } +range_check_ptr}() -> (res: felt) { + return (res=100); +} @external func double_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, - range_check_ptr}() -> (res: felt) { - let multiplier = 2; - let (balance) = get_balance(); - let new_balance = balance * multiplier; - return (res=new_balance); - } +range_check_ptr}() -> (res: felt) { + let multiplier = 2; + let (balance) = get_balance(); + let new_balance = balance * multiplier; + return (res=new_balance); +} ``` If you run that code, you'll run into the revoked reference error as we are @@ -559,20 +559,20 @@ trying to access the `multiplier` variable after calling the `get_balance` function. In simple cases you can resolve revoked references by adding the keyword -`alloc_locals` within function scopes. In most complex cases you might need to +`alloc_locals` within function scopes. In more complex cases you might need to create a local variable to resolve it. ```cairo // resolving the `double_balance` function: @external func double_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, - range_check_ptr}() -> (res: felt) { - alloc_locals; - let multiplier = 2; - let (balance) = get_balance(); - let new_balance = balance * multiplier; - return (res=new_balance); - } +range_check_ptr}() -> (res: felt) { + alloc_locals; + let multiplier = 2; + let (balance) = get_balance(); + let new_balance = balance * multiplier; + return (res=new_balance); +} ``` ### 12. Understanding Cairo's Punctuations @@ -627,7 +627,7 @@ const ACCOUNT_BALANCE_BOUND = 1073741; // (2 ** 30 / 1000) // // @dev A map from account and token type to corresponding balance @storage_var -func account_balance(account_id: felt, token_type: felt) -> (balance: felt){} +func account_balance(account_id: felt, token_type: felt) -> (balance: felt) {} // @dev a map from token type to corresponding pool balance @storage_var @@ -641,21 +641,21 @@ func pool_balance(token_type: felt) -> (balance: felt) {} // @param token_type Token to be queried @view func get_account_token_balance{syscall_ptr: felt*, pedersen_ptr: - HashBuiltin*, range_check_ptr}( - account_id: felt, token_type: felt - ) -> (balance: felt) { - return account_balance.read(account_id, token_type); - } +HashBuiltin*, range_check_ptr}( + account_id: felt, token_type: felt + ) -> (balance: felt) { + return account_balance.read(account_id, token_type); +} // @dev return the pool's balance // @param token_type Token type to get pool balance @view func get_pool_token_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, - range_check_ptr}( - token_type: felt - ) -> (balance: felt) { - return pool_balance.read(token_type); - } +range_check_ptr}( + token_type: felt + ) -> (balance: felt) { + return pool_balance.read(token_type); +} // EXTERNALS @@ -665,55 +665,55 @@ func get_pool_token_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, // @param balance Amount to be set as balance @external func set_pool_token_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, - range_check_ptr}( - token_type: felt, balance: felt - ) { - with_attr error_message("exceeds maximum allowed tokens!"){ - assert_nn_le(balance, BALANCE_UPPER_BOUND - 1); - } +range_check_ptr}( + token_type: felt, balance: felt + ) { + with_attr error_message("exceeds maximum allowed tokens!"){ + assert_nn_le(balance, BALANCE_UPPER_BOUND - 1); + } pool_balance.write(token_type, balance); return (); - } +} // @dev add demo token to the given account // @param token_a_amount amount of token a to be added // @param token_b_amount amount of token b to be added @external func add_demo_token{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, - range_check_ptr}( +range_check_ptr}( token_a_amount: felt, token_b_amount: felt ) { - alloc_locals; - let (account_id) = get_caller_address(); + alloc_locals; + let (account_id) = get_caller_address(); - modify_account_balance(account_id=account_id, token_type=TOKEN_TYPE_A, - amount=token_a_amount); - modify_account_balance(account_id=account_id, token_type=TOKEN_TYPE_B, - amount=token_b_amount); + modify_account_balance(account_id=account_id, token_type=TOKEN_TYPE_A, + amount=token_a_amount); + modify_account_balance(account_id=account_id, token_type=TOKEN_TYPE_B, + amount=token_b_amount); - return (); - } + return (); +} // @dev intialize AMM // @param token_a amount of token a to be set in pool // @param token_b amount of token b to be set in pool @external func init_pool{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, - range_check_ptr}( - token_a: felt, token_b: felt - ) { - with_attr error_message("exceeds maximum allowed tokens!"){ - assert_nn_le(token_a, POOL_UPPER_BOUND - 1); - assert_nn_le(token_b, POOL_UPPER_BOUND - 1); - } - - set_pool_token_balance(token_type=TOKEN_TYPE_A, balance=token_a); - set_pool_token_balance(token_type=TOKEN_TYPE_B, balance=token_b); - - return (); +range_check_ptr}( + token_a: felt, token_b: felt + ) { + with_attr error_message("exceeds maximum allowed tokens!"){ + assert_nn_le(token_a, POOL_UPPER_BOUND - 1); + assert_nn_le(token_b, POOL_UPPER_BOUND - 1); } + set_pool_token_balance(token_type=TOKEN_TYPE_A, balance=token_a); + set_pool_token_balance(token_type=TOKEN_TYPE_B, balance=token_b); + + return (); +} + // @dev swaps token between the given account and the pool // @param token_from token to be swapped @@ -723,32 +723,32 @@ func init_pool{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, func swap{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( token_from: felt, amount_from: felt ) -> (amount_to: felt) { - alloc_locals; - let (account_id) = get_caller_address(); + alloc_locals; + let (account_id) = get_caller_address(); - // verify token_from is TOKEN_TYPE_A or TOKEN_TYPE_B - with_attr error_message("token not allowed in pool!"){ - assert (token_from - TOKEN_TYPE_A) * (token_from - TOKEN_TYPE_B) = 0; - } + // verify token_from is TOKEN_TYPE_A or TOKEN_TYPE_B + with_attr error_message("token not allowed in pool!"){ + assert (token_from - TOKEN_TYPE_A) * (token_from - TOKEN_TYPE_B) = 0; + } - // check requested amount_from is valid - with_attr error_message("exceeds maximum allowed tokens!"){ - assert_nn_le(amount_from, BALANCE_UPPER_BOUND - 1); - } + // check requested amount_from is valid + with_attr error_message("exceeds maximum allowed tokens!"){ + assert_nn_le(amount_from, BALANCE_UPPER_BOUND - 1); + } - // check user has enough funds - let (account_from_balance) = - get_account_token_balance(account_id=account_id, token_type=token_from); - with_attr error_message("insufficient balance!"){ - assert_le(amount_from, account_from_balance); - } + // check user has enough funds + let (account_from_balance) = + get_account_token_balance(account_id=account_id, token_type=token_from); + with_attr error_message("insufficient balance!"){ + assert_le(amount_from, account_from_balance); + } - let (token_to) = get_opposite_token(token_type=token_from); - let (amount_to) = do_swap(account_id=account_id, token_from=token_from, - token_to=token_to, amount_from=amount_from); + let (token_to) = get_opposite_token(token_type=token_from); + let (amount_to) = do_swap(account_id=account_id, token_from=token_from, + token_to=token_to, amount_from=amount_from); - return (amount_to=amount_to); - } + return (amount_to=amount_to); +} // INTERNALS @@ -761,17 +761,17 @@ func modify_account_balance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( account_id: felt, token_type: felt, amount: felt ) { - let (current_balance) = account_balance.read(account_id, token_type); - tempvar new_balance = current_balance + amount; + let (current_balance) = account_balance.read(account_id, token_type); + tempvar new_balance = current_balance + amount; - with_attr error_message("exceeds maximum allowed tokens!"){ - assert_nn_le(new_balance, BALANCE_UPPER_BOUND - 1); - } + with_attr error_message("exceeds maximum allowed tokens!"){ + assert_nn_le(new_balance, BALANCE_UPPER_BOUND - 1); + } - account_balance.write(account_id=account_id, token_type=token_type, - value=new_balance); - return (); - } + account_balance.write(account_id=account_id, token_type=token_type, + value=new_balance); + return (); +} // @dev internal function that swaps tokens between the given account and // the pool @@ -783,31 +783,31 @@ func do_swap{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( account_id: felt, token_from: felt, token_to: felt, amount_from: felt ) -> (amount_to: felt) { - alloc_locals; + alloc_locals; - // get pool balance - let (local amm_from_balance) = get_pool_token_balance(token_type = - token_from); - let (local amm_to_balance) = get_pool_token_balance(token_type=token_to); + // get pool balance + let (local amm_from_balance) = get_pool_token_balance(token_type = + token_from); + let (local amm_to_balance) = get_pool_token_balance(token_type=token_to); - // calculate swap amount - let (local amount_to, _) = unsigned_div_rem((amm_to_balance * - amount_from), (amm_from_balance + amount_from)); + // calculate swap amount + let (local amount_to, _) = unsigned_div_rem((amm_to_balance * + amount_from), (amm_from_balance + amount_from)); - // update token_from balances - modify_account_balance(account_id=account_id, token_type=token_from, - amount=-amount_from); - set_pool_token_balance(token_type=token_from, balance=(amm_from_balance - + amount_from)); + // update token_from balances + modify_account_balance(account_id=account_id, token_type=token_from, + amount=-amount_from); + set_pool_token_balance(token_type=token_from, balance=(amm_from_balance + + amount_from)); - // update token_to balances - modify_account_balance(account_id=account_id, token_type=token_to, - amount=amount_to); - set_pool_token_balance(token_type=token_to, balance=(amm_to_balance - - amount_to)); + // update token_to balances + modify_account_balance(account_id=account_id, token_type=token_to, + amount=amount_to); + set_pool_token_balance(token_type=token_to, balance=(amm_to_balance - + amount_to)); - return (amount_to=amount_to); - } + return (amount_to=amount_to); +} // @dev internal function to get the opposite token type