diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/caller.mligo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/caller.mligo deleted file mode 100644 index e04f9b9..0000000 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/caller.mligo +++ /dev/null @@ -1,72 +0,0 @@ -#include "tzip/proposals/tzip-12/lib/fa2_hook_lib.mligo" -#include "tzip/proposals/tzip-12/lib/fa2_behaviors.mligo" - -type storage = { - fa2_registry : fa2_registry; - descriptor : permissions_descriptor; - rep : balance_of_response_michelson list -} - -type request_balance_of_param = { - at : address; - requests : balance_of_request list; -} - -type receive_balance_of_param = balance_of_response_michelson list - -let request_balance (req, s : (request_balance_of_param * storage)) : operation list * storage = - // Get the TZIP-12 contract instance 'from' the chain - let token_contract_balance_entrypoint_opt : balance_of_param_michelson contract option = Tezos.get_entrypoint_opt "%balance_of" req.at in - let token_contract_balance_entrypoint : balance_of_param_michelson contract = match (token_contract_balance_entrypoint_opt) with - | Some (ci) -> ci - | None -> (failwith("Entrypoint not found"): balance_of_param_michelson contract) - in - - // Callback (contract) for Balance_of will be the current contract's Receive_balance entrypoint - let balance_of_callback_contract_opt : receive_balance_of_param contract option = Tezos.get_entrypoint_opt "%receive_balance" Tezos.self_address in - let balance_of_callback_contract : receive_balance_of_param contract = match (balance_of_callback_contract_opt) with - | Some (ci) -> ci - | None -> (failwith("Entrypoint not found"): receive_balance_of_param contract) - in - //let balance_of_callback_contract : receive_balance_of_param contract = get_entrypoint("%receive_balance", Tezos.self_address) in - // Set up the parameter w/ data required for the Balance_of entrypoint - let convert = fun (i : balance_of_request) -> Layout.convert_to_right_comb(i) in - let request_michelson : balance_of_request_michelson list = List.map convert req.requests in - let balance_of_operation_param : balance_of_param_aux = { - requests = request_michelson; - callback = balance_of_callback_contract; - } in - let reqPayload : balance_of_param_michelson = Layout.convert_to_right_comb(balance_of_operation_param) in - // Forge an internal transaction to the TZIP-12 contract - // parametrised by the prieviously prepared `balance_of_operation_param` - // Note: We're sending 0mutez as part of this transaction - let balance_of_operation : operation = Tezos.transaction reqPayload 0mutez token_contract_balance_entrypoint in - ([ balance_of_operation ], s) - -let receive_balance (received, s: (receive_balance_of_param * storage)) : operation list * storage = - let new_store : storage = { s with rep = received } in - (([] : operation list), new_store) - -type entry_points = - | Request_balance of request_balance_of_param - | Receive_balance of receive_balance_of_param - | Tokens_transferred_hook of transfer_descriptor_param_michelson - | Register_with_fa2 of fa2_with_hook_entry_points contract - - let main (param, s : entry_points * storage) - : (operation list) * storage = - match param with - | Tokens_transferred_hook pm -> - let p = transfer_descriptor_param_from_michelson pm in - let u = validate_hook_call (p.fa2, s.fa2_registry) in - let ops = standard_transfer_hook ( - {ligo_param = p; michelson_param = pm}, s.descriptor) in - ops, s - - | Register_with_fa2 fa2 -> - let op , new_registry = register_with_fa2 (fa2, s.descriptor, s.fa2_registry) in - let new_s = { s with fa2_registry = new_registry; } in - [op], new_s - - | Request_balance request_balance_of_param -> request_balance (request_balance_of_param, s) - | Receive_balance receive_balance_of_param -> receive_balance (receive_balance_of_param, s) diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/caller.religo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/caller.religo new file mode 100644 index 0000000..6914e77 --- /dev/null +++ b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/caller.religo @@ -0,0 +1,60 @@ +// Fa2 Client contract +#include "tzip-12/fa2_interface.religo" + +type storage = { + rep : list(balanceOfResponseMichelson) +} + +type request_balance_of_param = { + at : address, + requests : list(balanceOfRequest) +} + +type receive_balance_of_param = list(balanceOfResponseMichelson) + +type entry_points = + | Request_balance (request_balance_of_param) + | Receive_balance (receive_balance_of_param) + +let request_balance = ((req, s) : (request_balance_of_param, storage)) : (list(operation), storage) => +{ + // Get the TZIP-12 contract instance 'from' the chain + let token_contract_balance_entrypoint_opt : option(contract(balanceOfParameterMichelson)) = Tezos.get_entrypoint_opt ("%balance_of", req.at) ; + let token_contract_balance_entrypoint : contract(balanceOfParameterMichelson) = switch (token_contract_balance_entrypoint_opt) { + | Some (ci) => ci + | None => (failwith("Entrypoint not found"): contract(balanceOfParameterMichelson)) + }; + + // Callback (contract) for Balance_of will be the current contract's Receive_balance entrypoint + let balance_of_callback_contract_opt : option(contract(receive_balance_of_param)) = Tezos.get_entrypoint_opt ("%receive_balance", Tezos.self_address); + let balance_of_callback_contract : contract(receive_balance_of_param) = switch (balance_of_callback_contract_opt) { + | Some (ci) => ci + | None => (failwith("Entrypoint not found"): contract(receive_balance_of_param)) + }; + + // Set up the parameter w/ data required for the Balance_of entrypoint + let convert = (i : balanceOfRequest) : balanceOfRequestMichelson => Layout.convert_to_right_comb(i); + let request_michelson : list(balanceOfRequestMichelson) = List.map (convert, req.requests); + let balance_of_operation_param : balanceOfParameterAuxiliary = { + requests : request_michelson, + callback : balance_of_callback_contract, + }; + let reqPayload : balanceOfParameterMichelson = Layout.convert_to_right_comb(balance_of_operation_param); + // Forge an internal transaction to the TZIP-12 contract from balance_of_operation_param. We're sending 0mutez as part of this transaction + let balance_of_operation : operation = Tezos.transaction (reqPayload, 0mutez, token_contract_balance_entrypoint); + ([ balance_of_operation ], s) +} + +let receive_balance = ((received, s): (receive_balance_of_param, storage)) : (list(operation), storage) => +{ + let new_store : storage = { ...s, rep : received }; + (([] :list( operation)), new_store) +} + +let main = ((param, s) : (entry_points , storage)) : (list(operation), storage) => +{ + switch (param) { + | Request_balance request_balance_of_param => request_balance ((request_balance_of_param, s)) + | Receive_balance receive_balance_of_param => receive_balance ((receive_balance_of_param, s)) + } +} \ No newline at end of file diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/course.md b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/course.md index 93cb9f3..030405e 100644 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/course.md +++ b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/course.md @@ -43,10 +43,6 @@ type parameter = | Update_operators(updateOperatorsParameter) ``` - - - - ### Balance of The FA2 client (contracts using our token) may need to know the balance of a owner. The FA2 standard specifies an entry point _Balance of_ which use a callback in order to send the balance information to the calling contract. @@ -208,20 +204,24 @@ Error mnemonic - Description ## Your mission -We are working on a fungible/multi-asset token compliant with the FA2 standard. We want you to complete the existing implementation of token. The *Total\_supply* entry point is not yet implemented , please finish the job ! +We are working on a fungible token compliant with the FA2 standard. We want you to complete the existing implementation of token. The *Balance\_Of* entry point is not yet implemented , please finish the job ! + +The function *balanceOfRequestsIterator* is responsible for processing each request and providing a response to each request.As you can see, a request is of type *balanceOfRequestMichelson* + -1 - Modify the *get\_total\_supply* lambda function in order to retrieve the *total\_supply* information related to the given *token\_id* list. +1- First, we need to retieve information from the request. convert the request *balanceOfRequestMichelson* into a vairiable named *balanceOfRequest* of type _balanceOfRequest_. You can use the *convert\_from\_right\_comb* function (seen in Chapter Interop) -2 - the *get\_total\_supply* lambda function For each given *token\_id*, find the given *token\_id* in the *tokens* map and retrieve the *total\_supply* associated to a given *token\_id* in the *tokens* map. +2- Now that request is readable, call the *getTokenBalance* function in order to retrieve the balance of the specified owner. Store the result in a variable *tokenBalance* of type _tokenBalance_. -3 -If a given *token\_id* is found then the function *get\_total\_supply* must return a *total\_supply\_response* record for each given *token\_id*. As seen in the interface the *total\_supply\_response* record contains *token\_id* and *total\_supply* fields. (use v as temporary variable for the match with instruction) +3- Now, we need to build a response for the balanceOfRequest. Declare a variable *balanceOfResponseAuxiliary* ot type _balanceOfResponseAuxiliary_ which contains the request and the retrieved balance *tokenBalance* (defined in the previous line). -4 -If a given *token\_id* is not found then the function *get\_total\_supply* must throw an exception with the predefined error messsage *token\_undefined*. +4- Convert this response of type _balanceOfResponseAuxiliary_ into a variable *balanceOfResponseMichelson* of type _balanceOfResponseMichelson_. You can use the *convert\_from\_right\_comb* function (seen in Chapter Interop) +## WIP ### Metadata diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/exercise.mligo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/exercise.mligo deleted file mode 100644 index 5f3484f..0000000 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/exercise.mligo +++ /dev/null @@ -1,193 +0,0 @@ -#include "tzip/proposals/tzip-12/fa2_interface.mligo" -#include "tzip/proposals/tzip-12/fa2_errors.mligo" - -type entity = { - balance : nat -} -type entity_key = address * token_id -type ledger = (entity_key, entity) map - -type tokens = { - total_supply : nat; - metadata : token_metadata; -} - -type storage = { - paused : bool; - ledger : ledger; - tokens : (token_id,tokens) map; - operators : operator_param set; - administrator : address; - permissions_descriptor : permissions_descriptor_aux; -} - -type return = (operation list * storage) - -type entry_points = - | Set_pause of bool - | Set_administrator of address - -type total_entry_points = (fa2_entry_points, "fa2_ep", entry_points, "specific_ep") michelson_or - -let set_pause(param,s : bool * storage): return = - if Tezos.sender = s.administrator then - (([] : operation list), { s with paused=param }) - else - (failwith("only admin can do it") : return) - -let set_administrator(param,s : address * storage): return = - if Tezos.sender = s.administrator then - (([] : operation list), { s with administrator=param }) - else - (failwith("only admin can do it") : return) - -let balance_of (param, s : balance_of_param_michelson * storage) : return = - let param_bo_aux : balance_of_param_aux = Layout.convert_from_right_comb(param: balance_of_param_michelson) in - let get_balance = fun ( i : balance_of_request_michelson) -> - let bor : balance_of_request = Layout.convert_from_right_comb(i) in - match Map.find_opt (bor.owner,bor.token_id) s.ledger with - | Some e -> { request = Layout.convert_to_right_comb(bor) ; balance =e.balance } - | None -> (failwith("unknown owner") : balance_of_response_aux) - in - let balance_of_callback_param : balance_of_response_aux list = List.map get_balance param_bo_aux.requests in - let convert = fun ( r : balance_of_response_aux) -> Layout.convert_to_right_comb(r) in - let balance_of_callback_param_michelson : balance_of_response_michelson list = List.map convert balance_of_callback_param in - // sending back the processed map of balance requests/responses - let destination: (balance_of_response_michelson list) contract = param_bo_aux.callback in - let balance_of_response_operation : operation = Tezos.transaction balance_of_callback_param_michelson 0mutez destination in - ([balance_of_response_operation], s) - -let total_supply(params, s: total_supply_param_michelson * storage) : return = - if s.paused = true then - (failwith("contract in pause") : return) - else - let p : total_supply_param = Layout.convert_from_right_comb(params: total_supply_param_michelson) in - let token_ids : token_id list = p.token_ids in - // Modify the code below - let get_total_supply = - in - let responses : total_supply_response list = List.map get_total_supply token_ids in - let convert = fun ( r : total_supply_response) -> Layout.convert_to_right_comb(r) in - let ret : total_supply_response_michelson list = List.map convert responses in - let destination: (total_supply_response_michelson list) contract = p.callback in - let op : operation = Tezos.transaction ret 0mutez destination in - ([ op ], s) - -let token_metadata(params, s: token_metadata_param_michelson * storage) : return = - if s.paused = true then - (failwith("contract in pause") : return) - else - let p : token_metadata_param = Layout.convert_from_right_comb(params: token_metadata_param_michelson) in - let token_ids : token_id list = p.token_ids in - let get_metadata = fun ( i : token_id) -> match Map.find_opt i s.tokens with - | Some v -> v.metadata - | None -> (failwith(token_undefined) : token_metadata) - in - let responses : token_metadata list = List.map get_metadata token_ids in - let convert = fun ( r : token_metadata) -> Layout.convert_to_right_comb(r) in - let ret : token_metadata_michelson list = List.map convert responses in - let destination: (token_metadata_michelson list) contract = p.callback in - let op : operation = Tezos.transaction ret 0mutez destination in - ([ op ], s) - -let transfer(params, s: transfer_michelson list * storage) : return = - if s.paused = true then - (failwith("contract in pause") : return) - else - let apply_transfer = fun (l,i : ledger * transfer_michelson) -> - let t_aux : transfer_aux = Layout.convert_from_right_comb(i: transfer_michelson) in - let from_ : address = t_aux.from_ in - let result_ledger : ledger = if Tezos.sender = from_ or Tezos.sender = s.administrator then - if Set.mem {owner=from_;operator=Tezos.sender} s.operators then - let transfers : transfer_destination_michelson list = t_aux.txs in - let apply_transfer_destination = fun (acc,j : (ledger * transfer_destination_michelson)) -> - let transfer_destination : transfer_destination = Layout.convert_from_right_comb(j: transfer_destination_michelson) in - let tr_amount : nat = transfer_destination.amount in - let to_ : address = transfer_destination.to_ in - let tokenid : token_id = transfer_destination.token_id in - let temp_state_ledger : ledger = if tr_amount > 0n then - let enough_funds : bool = match Map.find_opt (from_,tokenid) acc with - | Some bal -> (bal.balance >= tr_amount) - | None -> false - in - if enough_funds then - let l_updated_from : ledger = match Map.find_opt (from_,tokenid) acc with - | Some bal -> Map.update (from_,tokenid) (Some {balance=abs(bal.balance - tr_amount)} ) acc - | None -> (failwith("should not arrive here") : ledger) - in - let l_updated_from_to : ledger = match Map.find_opt (to_,tokenid) l_updated_from with - | Some bal -> Map.update (to_,tokenid) (Some {balance=bal.balance + tr_amount}) l_updated_from - | None -> Map.add (to_,tokenid) {balance=tr_amount} l_updated_from - in - l_updated_from_to - else - (failwith(insufficient_balance) : ledger) - else - (failwith("transferring nothing !") : ledger) - in - temp_state_ledger - in - let result : ledger = List.fold apply_transfer_destination transfers l in - result - else - (failwith(not_operator) : ledger) - else - (failwith(not_owner) : ledger) - in - result_ledger - in - let new_ledger : ledger = List.fold apply_transfer params s.ledger in - (([] : operation list), {s with ledger=new_ledger}) - -let update_operators (params,s : (update_operator_michelson list * storage)) : return = - if Tezos.sender <> s.administrator then - (failwith("operators can only be modified by the admin") : return) - else - let convert = fun (i : update_operator_michelson) -> (Layout.convert_from_right_comb(i) : update_operator_aux) in - let params_aux_list : update_operator_aux list = List.map convert params in - let apply_order = fun (acc,j : operator_param set * update_operator_aux) -> - match j with - | Add_operator opm -> - let p : operator_param = Layout.convert_from_right_comb(opm) in - if (Tezos.sender = p.owner or Tezos.sender = s.administrator) then - Set.add p acc - else - (failwith("notautorized !!!! ") : operator_param set) - | Remove_operator opm -> - let p : operator_param = Layout.convert_from_right_comb(opm) in - if (Tezos.sender = p.owner or Tezos.sender = s.administrator) then - Set.remove p acc - else - (failwith("notautorized !!!! ") : operator_param set) - in - let new_operators : operator_param set = List.fold apply_order params_aux_list s.operators in - (([] : operation list), {s with operators=new_operators}) - -let is_operator(params,s : (is_operator_param_michelson * storage)) : return = - let p : is_operator_param_aux = Layout.convert_from_right_comb(params) in - let op_param : operator_param = Layout.convert_from_right_comb(p.operator) in - let response_aux : is_operator_response_aux = {operator=p.operator;is_operator=Set.mem op_param s.operators} in - let response : is_operator_response_michelson = Layout.convert_to_right_comb(response_aux) in - let destination: (is_operator_response_michelson) contract = p.callback in - let op : operation = Tezos.transaction response 0mutez destination in - ([ op ], s) - -let send_permissions_descriptor(param,s : (permissions_descriptor_michelson contract * storage)) : return = - let response : permissions_descriptor_michelson = Layout.convert_to_right_comb(s.permissions_descriptor) in - let destination: permissions_descriptor_michelson contract = param in - let op : operation = Tezos.transaction response 0mutez destination in - ([ op ], s) - -let main (param,s : total_entry_points * storage) : return = - match param with - | M_left fa2_ep -> (match fa2_ep with - | Transfer l -> transfer (l, s) - | Balance_of p -> balance_of (p, s) - | Total_supply p -> total_supply (p,s) - | Token_metadata p -> token_metadata (p,s) - | Permissions_descriptor callback -> send_permissions_descriptor (callback, s) - | Update_operators l -> update_operators (l,s) - | Is_operator o -> is_operator (o,s)) - | M_right specific_ep -> (match specific_ep with - | Set_pause p -> set_pause (p,s) - | Set_administrator p -> set_administrator (p,s)) diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/exercise.religo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/exercise.religo new file mode 100644 index 0000000..1d877f2 --- /dev/null +++ b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/exercise.religo @@ -0,0 +1,248 @@ +// Fungible Token in ReasonLigo +#include "tzip-12/fa2_interface.religo" +#include "tzip-12/errors.religo" + +type tokenOperatorsSet = set(tokenOperator); +type tokenOperators = map(tokenOwner, tokenOperatorsSet); + +type tokenLookupId = (tokenOwner, tokenId); +type tokensLedger = big_map(tokenLookupId, tokenBalance); + +type storage = { + tokensLedger: tokensLedger, + tokenOperators: tokenOperators +}; + +type custom_entry_points = +| Mint ((tokenAmount, tokenOwner)) +| Burn ((tokenAmount, tokenOwner)) + +type ft_entry_points = +| Fa2 (parameter) +| Asset (custom_entry_points) + +type entrypointParameter = (ft_entry_points, storage); +type entrypointReturn = (list(operation), storage); + +//// HELPERS ////// +let defaultBalance: tokenBalance = 0n; +let getTokenBalance = ((tokenId, tokenOwner, storage): (tokenId, tokenOwner, storage)): tokenBalance => { + let tokensLedger: tokensLedger = storage.tokensLedger; + let tokenLookupId: tokenLookupId = (tokenOwner, tokenId); + let tokenBalance: option(tokenBalance) = Map.find_opt(tokenLookupId, tokensLedger); + switch (tokenBalance) { + | None => defaultBalance + | Some(tokenBalance) => tokenBalance + } +} + +let updateTokensLedger = ((transferFrom, fromTokenBalance, transferContents, storage): (tokenOwner, tokenBalance, transferContents, storage)): storage => { + let tokenId: tokenId = transferContents.token_id; + let transferTo: tokenOwner = transferContents.to_; + let transferAmount: tokenAmount = transferContents.amount; + let tokensLedger: tokensLedger = storage.tokensLedger; + + let tokenLookupIdFrom = (transferFrom, tokenId); + let tokenLookupIdTo = (transferTo, tokenId); + let balanceTo: tokenBalance = getTokenBalance((tokenId, transferTo, storage)); + // update balance from + let tokensLedger = Map.update( + tokenLookupIdFrom, + Some(abs(fromTokenBalance - transferAmount)), + tokensLedger + ); + // update balance to + let tokensLedger = Map.update( + tokenLookupIdTo, + Some(balanceTo + transferAmount), + tokensLedger + ); + let storage = { + ...storage, + tokensLedger: tokensLedger + }; + storage +} + +let currentPermissionsDescriptor: permissionsDescriptor = { + operator: Owner_or_operator_transfer, + receiver: Owner_no_hook, + sender: Owner_no_hook, + custom: (None: option(customPermissionPolicy)) +} + +let currentOperatorUpdatePermissionPolicy: operatorUpdatePolicy = Owner_update; + +// operatorUpdatePolicy = Owner_update +let canUpdateOperators = ((tokenOwner, storage): (tokenOwner, storage)): unit => { + if (Tezos.sender != tokenOwner) { + failwith(errorOperatorUpdateDenied) + } else { (); } +} + +let isOperator = ((tokenOwner, tokenOperator, storage): (tokenOwner, tokenOperator, storage)): bool => { + let tokenOperatorsSet: option(tokenOperatorsSet) = Map.find_opt(tokenOwner, storage.tokenOperators); + switch(tokenOperatorsSet) { + | None => false + | Some(tokenOperatorsSet) => Set.mem(tokenOperator, tokenOperatorsSet); + } +} + +// operatorTransferPolicy = Owner_or_operator_transfer +let canTransfer = ((from, transferContents, storage): (tokenOwner, transferContents, storage)): unit => { + if (from != Tezos.sender) { + if (!isOperator((from, Tezos.sender, storage))) { + failwith(errorNotOperator) + } else { (); } + } else { (); } +} + +///////////// BALANCEOF /////////// +type balanceOfRequestsIteratorAccumulator = (list(balanceOfResponseMichelson), storage); +let balanceOfRequestsIterator = + ((accumulator, balanceOfRequestMichelson): (balanceOfRequestsIteratorAccumulator, balanceOfRequestMichelson)): balanceOfRequestsIteratorAccumulator => { + let (balanceOfResponses, storage): balanceOfRequestsIteratorAccumulator = accumulator; + // Modify the code below + + let balanceOfResponses: list(balanceOfResponseMichelson) = [balanceOfResponseMichelson, ...balanceOfResponses]; + + (balanceOfResponses, storage); + } + +let balanceOf = ((balanceOfParameterMichelson, storage): (balanceOfParameterMichelson, storage)): entrypointReturn => { + let balanceOfParameter: balanceOfParameterAuxiliary = Layout.convert_from_right_comb(balanceOfParameterMichelson); + let (balanceOfResponses, _): balanceOfRequestsIteratorAccumulator = List.fold( + balanceOfRequestsIterator, + balanceOfParameter.requests, + (([]: list(balanceOfResponseMichelson)), storage) + ); + let callbackOperation: operation = Tezos.transaction(balanceOfResponses, 0tez, balanceOfParameter.callback); + ([callbackOperation], storage); +} + + +//////////////////////// TRANSFER ////////////////// + +type transferContentsIteratorAccumulator = (storage, tokenOwner); +let transferContentsIterator = ((accumulator, transferContentsMichelson): (transferContentsIteratorAccumulator, transferContentsMichelson)): transferContentsIteratorAccumulator => { + let (storage, from_) = accumulator; + let transferContents: transferContents = Layout.convert_from_right_comb(transferContentsMichelson); + let tokensLedger: tokensLedger = storage.tokensLedger; + let fromTokenBalance: tokenBalance = getTokenBalance((transferContents.token_id, from_, storage)); + + canTransfer((from_, transferContents, storage)); + + if (fromTokenBalance < transferContents.amount) { + (failwith(errorInsufficientBalance): transferContentsIteratorAccumulator); + } else { + let storage = updateTokensLedger((from_, fromTokenBalance, transferContents, storage)); + (storage, from_); + } +}; + +let transferIterator = ((storage, transferMichelson): (storage, transferMichelson)): storage => { + let transferAuxiliary: transferAuxiliary = Layout.convert_from_right_comb(transferMichelson); + let from_: tokenOwner = transferAuxiliary.from_; + + let (storage, _) = List.fold( + transferContentsIterator, + transferAuxiliary.txs, + (storage, from_) + ); + storage +}; + +let transfer = ((transferParameter, storage): (transferParameter, storage)): entrypointReturn => { + let storage = List.fold(transferIterator, transferParameter, storage); + (([]: list(operation)), storage); +}; + +///// PERMISSIONS DESCRIPTOR ///////////////// + +let permissionsDescriptor = ((permissionsDescriptorParameter, storage): (permissionsDescriptorParameter, storage)): entrypointReturn => { + let permissionsDescriptorAuxiliary: permissionsDescriptorAuxiliary = { + operator: Layout.convert_to_right_comb(currentPermissionsDescriptor.operator), + receiver: Layout.convert_to_right_comb(currentPermissionsDescriptor.receiver), + sender: Layout.convert_to_right_comb(currentPermissionsDescriptor.sender), + custom: (switch (currentPermissionsDescriptor.custom) { + | Some(custom) => Some(Layout.convert_to_right_comb(custom)) + | None => (None: option(customPermissionPolicyMichelson)) + }) + }; + let currentPermissionsDescriptorMichelson: permissionsDescriptorMichelson = Layout.convert_to_right_comb(permissionsDescriptorAuxiliary); + let callbackOperation: operation = Tezos.transaction(currentPermissionsDescriptorMichelson, 0tez, permissionsDescriptorParameter); + ([callbackOperation], storage) +} + +////////////////////////////////// OPERATOR /////////////////////////// +let updateOperators = ((storage, updateOperatorsAddOrRemoveAuxiliary, operatorParameterMichelson): (storage, updateOperatorsAddOrRemoveAuxiliary, operatorParameterMichelson)): storage => { + let operatorParameter: operatorParameter = Layout.convert_from_right_comb(operatorParameterMichelson); + + canUpdateOperators((operatorParameter.owner, storage)); + + let tokenOperatorsSet: option(tokenOperatorsSet) = Map.find_opt( + operatorParameter.owner, + storage.tokenOperators + ); + let tokenOperatorsSet: option(tokenOperatorsSet) = switch (updateOperatorsAddOrRemoveAuxiliary) { + | Add_operator(n) => { + switch (tokenOperatorsSet) { + | Some(tokenOperatorsSet) => Some(Set.add(operatorParameter.operator, tokenOperatorsSet)) + | None => Some(Set.literal([operatorParameter.operator])) + } + } + | Remove_operator(n) => { + switch (tokenOperatorsSet) { + | Some(tokenOperatorsSet) => Some(Set.remove(operatorParameter.operator, tokenOperatorsSet)) + | None => (None: option(tokenOperatorsSet)) + } + } + }; + + let tokenOperators: tokenOperators = Map.update( + operatorParameter.owner, + tokenOperatorsSet, + storage.tokenOperators + ); + + { + ...storage, + tokenOperators: tokenOperators + } +} + +let updateOperatorsIterator = ((storage, updateOperatorsAddOrRemoveMichelson): (storage, updateOperatorsAddOrRemoveMichelson)): storage => { + let updateOperatorsAddOrRemoveAuxiliary: updateOperatorsAddOrRemoveAuxiliary = Layout.convert_from_right_comb(updateOperatorsAddOrRemoveMichelson); + switch (updateOperatorsAddOrRemoveAuxiliary) { + | Add_operator(operatorParameterMichelson) => updateOperators((storage, updateOperatorsAddOrRemoveAuxiliary, operatorParameterMichelson)); + | Remove_operator(operatorParameterMichelson) => updateOperators((storage, updateOperatorsAddOrRemoveAuxiliary, operatorParameterMichelson)); + } +} + +let updateOperators = ((updateOperatorsParameter, storage): (updateOperatorsParameter, storage)): entrypointReturn => { + let storage = List.fold( + updateOperatorsIterator, + updateOperatorsParameter, + storage + ); + (([]: list(operation)), storage) +} + +let main = ((parameter, storage): entrypointParameter): entrypointReturn => { + switch (parameter) { + | Fa2 fa2 => { + switch (fa2) { + | Transfer(transferParameter) => transfer((transferParameter, storage)) + | Balance_of(balanceOfParameterMichelson) => balanceOf((balanceOfParameterMichelson, storage)) + | Permissions_descriptor(permissionsDescriptorParameter) => permissionsDescriptor((permissionsDescriptorParameter, storage)) + | Update_operators(updateOperatorsParameter) => updateOperators((updateOperatorsParameter, storage)) + } + } + | Asset ast => { + switch (ast) { + | Mint(mintParameter) => (([]: list(operation)), storage) //mint(mintParameter) + | Burn(burnParameter) => (([]: list(operation)), storage) //burn(burnParameter) + } + } + } +} \ No newline at end of file diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/fungible_token.mligo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/fungible_token.mligo deleted file mode 100644 index 2bfbe83..0000000 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/fungible_token.mligo +++ /dev/null @@ -1,194 +0,0 @@ -#include "tzip/proposals/tzip-12/fa2_interface.mligo" -#include "tzip/proposals/tzip-12/fa2_errors.mligo" - -type entity = { - balance : nat -} -type entity_key = address * token_id -type ledger = (entity_key, entity) map - -type tokens = { - total_supply : nat; - metadata : token_metadata; -} - -type storage = { - paused : bool; - ledger : ledger; - tokens : (token_id,tokens) map; - operators : operator_param set; - administrator : address; - permissions_descriptor : permissions_descriptor_aux; -} - -type return = (operation list * storage) - -type entry_points = - | Set_pause of bool - | Set_administrator of address - -type total_entry_points = (fa2_entry_points, "fa2_ep", entry_points, "specific_ep") michelson_or - -let set_pause(param,s : bool * storage): return = - if Tezos.sender = s.administrator then - (([] : operation list), { s with paused=param }) - else - (failwith("only admin can do it") : return) - -let set_administrator(param,s : address * storage): return = - if Tezos.sender = s.administrator then - (([] : operation list), { s with administrator=param }) - else - (failwith("only admin can do it") : return) - -let balance_of (param, s : balance_of_param_michelson * storage) : return = - let param_bo_aux : balance_of_param_aux = Layout.convert_from_right_comb(param: balance_of_param_michelson) in - let get_balance = fun ( i : balance_of_request_michelson) -> - let bor : balance_of_request = Layout.convert_from_right_comb(i) in - match Map.find_opt (bor.owner,bor.token_id) s.ledger with - | Some e -> { request = Layout.convert_to_right_comb(bor) ; balance =e.balance } - | None -> (failwith("unknown owner") : balance_of_response_aux) - in - let balance_of_callback_param : balance_of_response_aux list = List.map get_balance param_bo_aux.requests in - let convert = fun ( r : balance_of_response_aux) -> Layout.convert_to_right_comb(r) in - let balance_of_callback_param_michelson : balance_of_response_michelson list = List.map convert balance_of_callback_param in - // sending back the processed map of balance requests/responses - let destination: (balance_of_response_michelson list) contract = param_bo_aux.callback in - let balance_of_response_operation : operation = Tezos.transaction balance_of_callback_param_michelson 0mutez destination in - ([balance_of_response_operation], s) - -let total_supply(params, s: total_supply_param_michelson * storage) : return = - if s.paused = true then - (failwith("contract in pause") : return) - else - let p : total_supply_param = Layout.convert_from_right_comb(params: total_supply_param_michelson) in - let token_ids : token_id list = p.token_ids in - let get_total_supply = fun ( i : token_id) -> match Map.find_opt i s.tokens with - | Some v -> { token_id = i ; total_supply =v.total_supply } - | None -> (failwith(token_undefined) : total_supply_response) - in - let responses : total_supply_response list = List.map get_total_supply token_ids in - let convert = fun ( r : total_supply_response) -> Layout.convert_to_right_comb(r) in - let ret : total_supply_response_michelson list = List.map convert responses in - let destination: (total_supply_response_michelson list) contract = p.callback in - let op : operation = Tezos.transaction ret 0mutez destination in - ([ op ], s) - -let token_metadata(params, s: token_metadata_param_michelson * storage) : return = - if s.paused = true then - (failwith("contract in pause") : return) - else - let p : token_metadata_param = Layout.convert_from_right_comb(params: token_metadata_param_michelson) in - let token_ids : token_id list = p.token_ids in - let get_metadata = fun ( i : token_id) -> match Map.find_opt i s.tokens with - | Some v -> v.metadata - | None -> (failwith("unknown token_id") : token_metadata) - in - let responses : token_metadata list = List.map get_metadata token_ids in - let convert = fun ( r : token_metadata) -> Layout.convert_to_right_comb(r) in - let ret : token_metadata_michelson list = List.map convert responses in - let destination: (token_metadata_michelson list) contract = p.callback in - let op : operation = Tezos.transaction ret 0mutez destination in - ([ op ], s) - -let transfer(params, s: transfer_michelson list * storage) : return = - if s.paused = true then - (failwith("contract in pause") : return) - else - let apply_transfer = fun (l,i : ledger * transfer_michelson) -> - let t_aux : transfer_aux = Layout.convert_from_right_comb(i: transfer_michelson) in - let from_ : address = t_aux.from_ in - let result_ledger : ledger = if Tezos.sender = from_ or Tezos.sender = s.administrator then - if Set.mem {owner=from_;operator=Tezos.sender} s.operators then - let transfers : transfer_destination_michelson list = t_aux.txs in - let apply_transfer_destination = fun (acc,j : (ledger * transfer_destination_michelson)) -> - let transfer_destination : transfer_destination = Layout.convert_from_right_comb(j: transfer_destination_michelson) in - let tr_amount : nat = transfer_destination.amount in - let to_ : address = transfer_destination.to_ in - let tokenid : token_id = transfer_destination.token_id in - let temp_state_ledger : ledger = if tr_amount > 0n then - let enough_funds : bool = match Map.find_opt (from_,tokenid) acc with - | Some bal -> (bal.balance >= tr_amount) - | None -> false - in - if enough_funds then - let l_updated_from : ledger = match Map.find_opt (from_,tokenid) acc with - | Some bal -> Map.update (from_,tokenid) (Some {balance=abs(bal.balance - tr_amount)} ) acc - | None -> (failwith("should not arrive here") : ledger) - in - let l_updated_from_to : ledger = match Map.find_opt (to_,tokenid) l_updated_from with - | Some bal -> Map.update (to_,tokenid) (Some {balance=bal.balance + tr_amount}) l_updated_from - | None -> Map.add (to_,tokenid) {balance=tr_amount} l_updated_from - in - l_updated_from_to - else - (failwith(insufficient_balance) : ledger) - else - (failwith("transferring nothing !") : ledger) - in - temp_state_ledger - in - let result : ledger = List.fold apply_transfer_destination transfers l in - result - else - (failwith(not_operator) : ledger) - else - (failwith(not_owner) : ledger) - in - result_ledger - in - let new_ledger : ledger = List.fold apply_transfer params s.ledger in - (([] : operation list), {s with ledger=new_ledger}) - -let update_operators (params,s : (update_operator_michelson list * storage)) : return = - if Tezos.sender <> s.administrator then - (failwith("operators can only be modified by the admin") : return) - else - let convert = fun (i : update_operator_michelson) -> (Layout.convert_from_right_comb(i) : update_operator_aux) in - let params_aux_list : update_operator_aux list = List.map convert params in - let apply_order = fun (acc,j : operator_param set * update_operator_aux) -> - match j with - | Add_operator opm -> - let p : operator_param = Layout.convert_from_right_comb(opm) in - if (Tezos.sender = p.owner or Tezos.sender = s.administrator) then - Set.add p acc - else - (failwith("notautorized !!!! ") : operator_param set) - | Remove_operator opm -> - let p : operator_param = Layout.convert_from_right_comb(opm) in - if (Tezos.sender = p.owner or Tezos.sender = s.administrator) then - Set.remove p acc - else - (failwith("notautorized !!!! ") : operator_param set) - in - let new_operators : operator_param set = List.fold apply_order params_aux_list s.operators in - (([] : operation list), {s with operators=new_operators}) - -let is_operator(params,s : (is_operator_param_michelson * storage)) : return = - let p : is_operator_param_aux = Layout.convert_from_right_comb(params) in - let op_param : operator_param = Layout.convert_from_right_comb(p.operator) in - let response_aux : is_operator_response_aux = {operator=p.operator;is_operator=Set.mem op_param s.operators} in - let response : is_operator_response_michelson = Layout.convert_to_right_comb(response_aux) in - let destination: (is_operator_response_michelson) contract = p.callback in - let op : operation = Tezos.transaction response 0mutez destination in - ([ op ], s) - -let send_permissions_descriptor(param,s : (permissions_descriptor_michelson contract * storage)) : return = - let response : permissions_descriptor_michelson = Layout.convert_to_right_comb(s.permissions_descriptor) in - let destination: permissions_descriptor_michelson contract = param in - let op : operation = Tezos.transaction response 0mutez destination in - ([ op ], s) - -let main (param,s : total_entry_points * storage) : return = - match param with - | M_left fa2_ep -> (match fa2_ep with - | Transfer l -> transfer (l, s) - | Balance_of p -> balance_of (p, s) - | Total_supply p -> total_supply (p,s) - | Token_metadata p -> token_metadata (p,s) - | Permissions_descriptor callback -> send_permissions_descriptor (callback, s) - | Update_operators l -> update_operators (l,s) - | Is_operator o -> is_operator (o,s)) - | M_right specific_ep -> (match specific_ep with - | Set_pause p -> set_pause (p,s) - | Set_administrator p -> set_administrator (p,s)) diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/solution.mligo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/solution.mligo deleted file mode 100644 index 9b61bd0..0000000 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/solution.mligo +++ /dev/null @@ -1,195 +0,0 @@ -#include "tzip/proposals/tzip-12/fa2_interface.mligo" -#include "tzip/proposals/tzip-12/fa2_errors.mligo" - -type entity = { - balance : nat -} -type entity_key = address * token_id -type ledger = (entity_key, entity) map - -type tokens = { - total_supply : nat; - metadata : token_metadata; -} - -type storage = { - paused : bool; - ledger : ledger; - tokens : (token_id,tokens) map; - operators : operator_param set; - administrator : address; - permissions_descriptor : permissions_descriptor_aux; -} - -type return = (operation list * storage) - -type entry_points = - | Set_pause of bool - | Set_administrator of address - -type total_entry_points = (fa2_entry_points, "fa2_ep", entry_points, "specific_ep") michelson_or - -let set_pause(param,s : bool * storage): return = - if Tezos.sender = s.administrator then - (([] : operation list), { s with paused=param }) - else - (failwith("only admin can do it") : return) - -let set_administrator(param,s : address * storage): return = - if Tezos.sender = s.administrator then - (([] : operation list), { s with administrator=param }) - else - (failwith("only admin can do it") : return) - -let balance_of (param, s : balance_of_param_michelson * storage) : return = - let param_bo_aux : balance_of_param_aux = Layout.convert_from_right_comb(param: balance_of_param_michelson) in - let get_balance = fun ( i : balance_of_request_michelson) -> - let bor : balance_of_request = Layout.convert_from_right_comb(i) in - match Map.find_opt (bor.owner,bor.token_id) s.ledger with - | Some e -> { request = Layout.convert_to_right_comb(bor) ; balance =e.balance } - | None -> (failwith("unknown owner") : balance_of_response_aux) - in - let balance_of_callback_param : balance_of_response_aux list = List.map get_balance param_bo_aux.requests in - let convert = fun ( r : balance_of_response_aux) -> Layout.convert_to_right_comb(r) in - let balance_of_callback_param_michelson : balance_of_response_michelson list = List.map convert balance_of_callback_param in - // sending back the processed map of balance requests/responses - let destination: (balance_of_response_michelson list) contract = param_bo_aux.callback in - let balance_of_response_operation : operation = Tezos.transaction balance_of_callback_param_michelson 0mutez destination in - ([balance_of_response_operation], s) - -let total_supply(params, s: total_supply_param_michelson * storage) : return = - if s.paused = true then - (failwith("contract in pause") : return) - else - let p : total_supply_param = Layout.convert_from_right_comb(params: total_supply_param_michelson) in - let token_ids : token_id list = p.token_ids in - // Modify the code below - let get_total_supply = fun ( i : token_id) -> match Map.find_opt i s.tokens with - | Some v -> { token_id = i ; total_supply =v.total_supply } - | None -> (failwith(token_undefined) : total_supply_response) - in - let responses : total_supply_response list = List.map get_total_supply token_ids in - let convert = fun ( r : total_supply_response) -> Layout.convert_to_right_comb(r) in - let ret : total_supply_response_michelson list = List.map convert responses in - let destination: (total_supply_response_michelson list) contract = p.callback in - let op : operation = Tezos.transaction ret 0mutez destination in - ([ op ], s) - -let token_metadata(params, s: token_metadata_param_michelson * storage) : return = - if s.paused = true then - (failwith("contract in pause") : return) - else - let p : token_metadata_param = Layout.convert_from_right_comb(params: token_metadata_param_michelson) in - let token_ids : token_id list = p.token_ids in - let get_metadata = fun ( i : token_id) -> match Map.find_opt i s.tokens with - | Some v -> v.metadata - | None -> (failwith(token_undefined) : token_metadata) - in - let responses : token_metadata list = List.map get_metadata token_ids in - let convert = fun ( r : token_metadata) -> Layout.convert_to_right_comb(r) in - let ret : token_metadata_michelson list = List.map convert responses in - let destination: (token_metadata_michelson list) contract = p.callback in - let op : operation = Tezos.transaction ret 0mutez destination in - ([ op ], s) - -let transfer(params, s: transfer_michelson list * storage) : return = - if s.paused = true then - (failwith("contract in pause") : return) - else - let apply_transfer = fun (l,i : ledger * transfer_michelson) -> - let t_aux : transfer_aux = Layout.convert_from_right_comb(i: transfer_michelson) in - let from_ : address = t_aux.from_ in - let result_ledger : ledger = if Tezos.sender = from_ or Tezos.sender = s.administrator then - if Set.mem {owner=from_;operator=Tezos.sender} s.operators then - let transfers : transfer_destination_michelson list = t_aux.txs in - let apply_transfer_destination = fun (acc,j : (ledger * transfer_destination_michelson)) -> - let transfer_destination : transfer_destination = Layout.convert_from_right_comb(j: transfer_destination_michelson) in - let tr_amount : nat = transfer_destination.amount in - let to_ : address = transfer_destination.to_ in - let tokenid : token_id = transfer_destination.token_id in - let temp_state_ledger : ledger = if tr_amount > 0n then - let enough_funds : bool = match Map.find_opt (from_,tokenid) acc with - | Some bal -> (bal.balance >= tr_amount) - | None -> false - in - if enough_funds then - let l_updated_from : ledger = match Map.find_opt (from_,tokenid) acc with - | Some bal -> Map.update (from_,tokenid) (Some {balance=abs(bal.balance - tr_amount)} ) acc - | None -> (failwith("should not arrive here") : ledger) - in - let l_updated_from_to : ledger = match Map.find_opt (to_,tokenid) l_updated_from with - | Some bal -> Map.update (to_,tokenid) (Some {balance=bal.balance + tr_amount}) l_updated_from - | None -> Map.add (to_,tokenid) {balance=tr_amount} l_updated_from - in - l_updated_from_to - else - (failwith(insufficient_balance) : ledger) - else - (failwith("transferring nothing !") : ledger) - in - temp_state_ledger - in - let result : ledger = List.fold apply_transfer_destination transfers l in - result - else - (failwith(not_operator) : ledger) - else - (failwith(not_owner) : ledger) - in - result_ledger - in - let new_ledger : ledger = List.fold apply_transfer params s.ledger in - (([] : operation list), {s with ledger=new_ledger}) - -let update_operators (params,s : (update_operator_michelson list * storage)) : return = - if Tezos.sender <> s.administrator then - (failwith("operators can only be modified by the admin") : return) - else - let convert = fun (i : update_operator_michelson) -> (Layout.convert_from_right_comb(i) : update_operator_aux) in - let params_aux_list : update_operator_aux list = List.map convert params in - let apply_order = fun (acc,j : operator_param set * update_operator_aux) -> - match j with - | Add_operator opm -> - let p : operator_param = Layout.convert_from_right_comb(opm) in - if (Tezos.sender = p.owner or Tezos.sender = s.administrator) then - Set.add p acc - else - (failwith("notautorized !!!! ") : operator_param set) - | Remove_operator opm -> - let p : operator_param = Layout.convert_from_right_comb(opm) in - if (Tezos.sender = p.owner or Tezos.sender = s.administrator) then - Set.remove p acc - else - (failwith("notautorized !!!! ") : operator_param set) - in - let new_operators : operator_param set = List.fold apply_order params_aux_list s.operators in - (([] : operation list), {s with operators=new_operators}) - -let is_operator(params,s : (is_operator_param_michelson * storage)) : return = - let p : is_operator_param_aux = Layout.convert_from_right_comb(params) in - let op_param : operator_param = Layout.convert_from_right_comb(p.operator) in - let response_aux : is_operator_response_aux = {operator=p.operator;is_operator=Set.mem op_param s.operators} in - let response : is_operator_response_michelson = Layout.convert_to_right_comb(response_aux) in - let destination: (is_operator_response_michelson) contract = p.callback in - let op : operation = Tezos.transaction response 0mutez destination in - ([ op ], s) - -let send_permissions_descriptor(param,s : (permissions_descriptor_michelson contract * storage)) : return = - let response : permissions_descriptor_michelson = Layout.convert_to_right_comb(s.permissions_descriptor) in - let destination: permissions_descriptor_michelson contract = param in - let op : operation = Tezos.transaction response 0mutez destination in - ([ op ], s) - -let main (param,s : total_entry_points * storage) : return = - match param with - | M_left fa2_ep -> (match fa2_ep with - | Transfer l -> transfer (l, s) - | Balance_of p -> balance_of (p, s) - | Total_supply p -> total_supply (p,s) - | Token_metadata p -> token_metadata (p,s) - | Permissions_descriptor callback -> send_permissions_descriptor (callback, s) - | Update_operators l -> update_operators (l,s) - | Is_operator o -> is_operator (o,s)) - | M_right specific_ep -> (match specific_ep with - | Set_pause p -> set_pause (p,s) - | Set_administrator p -> set_administrator (p,s)) diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/solution.religo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/solution.religo new file mode 100644 index 0000000..9dcd436 --- /dev/null +++ b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/solution.religo @@ -0,0 +1,255 @@ +// Fungible Token in ReasonLigo +#include "tzip-12/fa2_interface.religo" +#include "tzip-12/errors.religo" + +type tokenOperatorsSet = set(tokenOperator); +type tokenOperators = map(tokenOwner, tokenOperatorsSet); + +type tokenLookupId = (tokenOwner, tokenId); +type tokensLedger = big_map(tokenLookupId, tokenBalance); + +type storage = { + tokensLedger: tokensLedger, + tokenOperators: tokenOperators +}; + +type custom_entry_points = +| Mint ((tokenAmount, tokenOwner)) +| Burn ((tokenAmount, tokenOwner)) + +type ft_entry_points = +| Fa2 (parameter) +| Asset (custom_entry_points) + +type entrypointParameter = (ft_entry_points, storage); +type entrypointReturn = (list(operation), storage); + +//// HELPERS ////// +let defaultBalance: tokenBalance = 0n; +let getTokenBalance = ((tokenId, tokenOwner, storage): (tokenId, tokenOwner, storage)): tokenBalance => { + let tokensLedger: tokensLedger = storage.tokensLedger; + let tokenLookupId: tokenLookupId = (tokenOwner, tokenId); + let tokenBalance: option(tokenBalance) = Map.find_opt(tokenLookupId, tokensLedger); + switch (tokenBalance) { + | None => defaultBalance + | Some(tokenBalance) => tokenBalance + } +} + +let updateTokensLedger = ((transferFrom, fromTokenBalance, transferContents, storage): (tokenOwner, tokenBalance, transferContents, storage)): storage => { + let tokenId: tokenId = transferContents.token_id; + let transferTo: tokenOwner = transferContents.to_; + let transferAmount: tokenAmount = transferContents.amount; + let tokensLedger: tokensLedger = storage.tokensLedger; + + let tokenLookupIdFrom = (transferFrom, tokenId); + let tokenLookupIdTo = (transferTo, tokenId); + let balanceTo: tokenBalance = getTokenBalance((tokenId, transferTo, storage)); + // update balance from + let tokensLedger = Map.update( + tokenLookupIdFrom, + Some(abs(fromTokenBalance - transferAmount)), + tokensLedger + ); + // update balance to + let tokensLedger = Map.update( + tokenLookupIdTo, + Some(balanceTo + transferAmount), + tokensLedger + ); + let storage = { + ...storage, + tokensLedger: tokensLedger + }; + storage +} + +let currentPermissionsDescriptor: permissionsDescriptor = { + operator: Owner_or_operator_transfer, + receiver: Owner_no_hook, + sender: Owner_no_hook, + custom: (None: option(customPermissionPolicy)) +} + +let currentOperatorUpdatePermissionPolicy: operatorUpdatePolicy = Owner_update; + +// operatorUpdatePolicy = Owner_update +let canUpdateOperators = ((tokenOwner, storage): (tokenOwner, storage)): unit => { + if (Tezos.sender != tokenOwner) { + failwith(errorOperatorUpdateDenied) + } else { (); } +} + +let isOperator = ((tokenOwner, tokenOperator, storage): (tokenOwner, tokenOperator, storage)): bool => { + let tokenOperatorsSet: option(tokenOperatorsSet) = Map.find_opt(tokenOwner, storage.tokenOperators); + switch(tokenOperatorsSet) { + | None => false + | Some(tokenOperatorsSet) => Set.mem(tokenOperator, tokenOperatorsSet); + } +} + +// operatorTransferPolicy = Owner_or_operator_transfer +let canTransfer = ((from, transferContents, storage): (tokenOwner, transferContents, storage)): unit => { + if (from != Tezos.sender) { + if (!isOperator((from, Tezos.sender, storage))) { + failwith(errorNotOperator) + } else { (); } + } else { (); } +} + +///////////// BALANCEOF /////////// +type balanceOfRequestsIteratorAccumulator = (list(balanceOfResponseMichelson), storage); +let balanceOfRequestsIterator = + ((accumulator, balanceOfRequestMichelson): (balanceOfRequestsIteratorAccumulator, balanceOfRequestMichelson)): balanceOfRequestsIteratorAccumulator => { + let (balanceOfResponses, storage): balanceOfRequestsIteratorAccumulator = accumulator; + // Modify the code below + let balanceOfRequest: balanceOfRequest = Layout.convert_from_right_comb(balanceOfRequestMichelson); + let tokenBalance: tokenBalance = getTokenBalance((balanceOfRequest.token_id, balanceOfRequest.owner, storage)); + let balanceOfResponseAuxiliary: balanceOfResponseAuxiliary = { + request: balanceOfRequestMichelson, + balance: tokenBalance + }; + let balanceOfResponseMichelson: balanceOfResponseMichelson = Layout.convert_to_right_comb(balanceOfResponseAuxiliary); + + let balanceOfResponses: list(balanceOfResponseMichelson) = [balanceOfResponseMichelson, ...balanceOfResponses]; + + (balanceOfResponses, storage); + } + +let balanceOf = ((balanceOfParameterMichelson, storage): (balanceOfParameterMichelson, storage)): entrypointReturn => { + let balanceOfParameter: balanceOfParameterAuxiliary = Layout.convert_from_right_comb(balanceOfParameterMichelson); + let (balanceOfResponses, _): balanceOfRequestsIteratorAccumulator = List.fold( + balanceOfRequestsIterator, + balanceOfParameter.requests, + (([]: list(balanceOfResponseMichelson)), storage) + ); + let callbackOperation: operation = Tezos.transaction(balanceOfResponses, 0tez, balanceOfParameter.callback); + ([callbackOperation], storage); +} + + +//////////////////////// TRANSFER ////////////////// + +type transferContentsIteratorAccumulator = (storage, tokenOwner); +let transferContentsIterator = ((accumulator, transferContentsMichelson): (transferContentsIteratorAccumulator, transferContentsMichelson)): transferContentsIteratorAccumulator => { + let (storage, from_) = accumulator; + let transferContents: transferContents = Layout.convert_from_right_comb(transferContentsMichelson); + let tokensLedger: tokensLedger = storage.tokensLedger; + let fromTokenBalance: tokenBalance = getTokenBalance((transferContents.token_id, from_, storage)); + + canTransfer((from_, transferContents, storage)); + + if (fromTokenBalance < transferContents.amount) { + (failwith(errorInsufficientBalance): transferContentsIteratorAccumulator); + } else { + let storage = updateTokensLedger((from_, fromTokenBalance, transferContents, storage)); + (storage, from_); + } +}; + +let transferIterator = ((storage, transferMichelson): (storage, transferMichelson)): storage => { + let transferAuxiliary: transferAuxiliary = Layout.convert_from_right_comb(transferMichelson); + let from_: tokenOwner = transferAuxiliary.from_; + + let (storage, _) = List.fold( + transferContentsIterator, + transferAuxiliary.txs, + (storage, from_) + ); + storage +}; + +let transfer = ((transferParameter, storage): (transferParameter, storage)): entrypointReturn => { + let storage = List.fold(transferIterator, transferParameter, storage); + (([]: list(operation)), storage); +}; + +///// PERMISSIONS DESCRIPTOR ///////////////// + +let permissionsDescriptor = ((permissionsDescriptorParameter, storage): (permissionsDescriptorParameter, storage)): entrypointReturn => { + let permissionsDescriptorAuxiliary: permissionsDescriptorAuxiliary = { + operator: Layout.convert_to_right_comb(currentPermissionsDescriptor.operator), + receiver: Layout.convert_to_right_comb(currentPermissionsDescriptor.receiver), + sender: Layout.convert_to_right_comb(currentPermissionsDescriptor.sender), + custom: (switch (currentPermissionsDescriptor.custom) { + | Some(custom) => Some(Layout.convert_to_right_comb(custom)) + | None => (None: option(customPermissionPolicyMichelson)) + }) + }; + let currentPermissionsDescriptorMichelson: permissionsDescriptorMichelson = Layout.convert_to_right_comb(permissionsDescriptorAuxiliary); + let callbackOperation: operation = Tezos.transaction(currentPermissionsDescriptorMichelson, 0tez, permissionsDescriptorParameter); + ([callbackOperation], storage) +} + +////////////////////////////////// OPERATOR /////////////////////////// +let updateOperators = ((storage, updateOperatorsAddOrRemoveAuxiliary, operatorParameterMichelson): (storage, updateOperatorsAddOrRemoveAuxiliary, operatorParameterMichelson)): storage => { + let operatorParameter: operatorParameter = Layout.convert_from_right_comb(operatorParameterMichelson); + + canUpdateOperators((operatorParameter.owner, storage)); + + let tokenOperatorsSet: option(tokenOperatorsSet) = Map.find_opt( + operatorParameter.owner, + storage.tokenOperators + ); + let tokenOperatorsSet: option(tokenOperatorsSet) = switch (updateOperatorsAddOrRemoveAuxiliary) { + | Add_operator(n) => { + switch (tokenOperatorsSet) { + | Some(tokenOperatorsSet) => Some(Set.add(operatorParameter.operator, tokenOperatorsSet)) + | None => Some(Set.literal([operatorParameter.operator])) + } + } + | Remove_operator(n) => { + switch (tokenOperatorsSet) { + | Some(tokenOperatorsSet) => Some(Set.remove(operatorParameter.operator, tokenOperatorsSet)) + | None => (None: option(tokenOperatorsSet)) + } + } + }; + + let tokenOperators: tokenOperators = Map.update( + operatorParameter.owner, + tokenOperatorsSet, + storage.tokenOperators + ); + + { + ...storage, + tokenOperators: tokenOperators + } +} + +let updateOperatorsIterator = ((storage, updateOperatorsAddOrRemoveMichelson): (storage, updateOperatorsAddOrRemoveMichelson)): storage => { + let updateOperatorsAddOrRemoveAuxiliary: updateOperatorsAddOrRemoveAuxiliary = Layout.convert_from_right_comb(updateOperatorsAddOrRemoveMichelson); + switch (updateOperatorsAddOrRemoveAuxiliary) { + | Add_operator(operatorParameterMichelson) => updateOperators((storage, updateOperatorsAddOrRemoveAuxiliary, operatorParameterMichelson)); + | Remove_operator(operatorParameterMichelson) => updateOperators((storage, updateOperatorsAddOrRemoveAuxiliary, operatorParameterMichelson)); + } +} + +let updateOperators = ((updateOperatorsParameter, storage): (updateOperatorsParameter, storage)): entrypointReturn => { + let storage = List.fold( + updateOperatorsIterator, + updateOperatorsParameter, + storage + ); + (([]: list(operation)), storage) +} + +let main = ((parameter, storage): entrypointParameter): entrypointReturn => { + switch (parameter) { + | Fa2 fa2 => { + switch (fa2) { + | Transfer(transferParameter) => transfer((transferParameter, storage)) + | Balance_of(balanceOfParameterMichelson) => balanceOf((balanceOfParameterMichelson, storage)) + | Permissions_descriptor(permissionsDescriptorParameter) => permissionsDescriptor((permissionsDescriptorParameter, storage)) + | Update_operators(updateOperatorsParameter) => updateOperators((updateOperatorsParameter, storage)) + } + } + | Asset ast => { + switch (ast) { + | Mint(mintParameter) => (([]: list(operation)), storage) //mint(mintParameter) + | Burn(burnParameter) => (([]: list(operation)), storage) //burn(burnParameter) + } + } + } +} \ No newline at end of file diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/errors.religo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/errors.religo new file mode 100644 index 0000000..1aa70a8 --- /dev/null +++ b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/errors.religo @@ -0,0 +1,20 @@ +let errorTokenUndefined = "FA2_TOKEN_UNDEFINED"; +let errorInsufficientBalance = "FA2_INSUFFICIENT_BALANCE"; + +/** + * Permission policy + */ +let errorNotOwner = "FA2_NOT_OWNER"; +let errorTransferDenied = "FA2_TX_DENIED"; +// This error may be deprecated depending on how the TZIP-12 spec evolves +let errorOperatorsUnsupported = "FA2_OPERATORS_UNSUPPORTED"; +let errorNotOperator = "FA2_NOT_OPERATOR"; +let errorOperatorUpdateDenied = "FA2_OPERATOR_UPDATE_DENIED"; // non-standard + +/** + * Hooks + */ +let errorReceiverHookFailed = "FA2_RECEIVER_HOOK_FAILED"; +let errorSenderHookFailed = "FA2_SENDER_HOOK_FAILED"; +let errorReceiverHookUndefined = "FA2_RECEIVER_HOOK_UNDEFINED"; +let errorSenderHookUndefined = "FA2_SENDER_HOOK_UNDEFINED"; \ No newline at end of file diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/fa2_errors.mligo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/fa2_errors.mligo deleted file mode 100644 index 506f2e8..0000000 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/fa2_errors.mligo +++ /dev/null @@ -1,44 +0,0 @@ -#if !FA2_ERRORS -#define FA2_ERRORS - -(** One of the specified `token_id`s is not defined within the FA2 contract *) -let token_undefined = "TOKEN_UNDEFINED" -(** -A token owner does not have sufficient balance to transfer tokens from -owner's account -*) -let insufficient_balance = "INSUFFICIENT_BALANCE" -(** A transfer failed because of `operator_transfer_policy == No_transfer` *) -let tx_denied = "TX_DENIED" -(** -A transfer failed because `operator_transfer_policy == Owner_transfer` and it is -initiated not by the token owner -*) -let not_owner = "NOT_OWNER" -(** -A transfer failed because `operator_transfer_policy == Owner_or_operator_transfer` -and it is initiated neither by the token owner nor a permitted operator - *) -let not_operator = "NOT_OPERATOR" -(** -Receiver hook is invoked and failed. This error MUST be raised by the hook -implementation - *) -let receiver_hook_failed = "RECEIVER_HOOK_FAILED" -(** -Sender hook is invoked and failed. This error MUST be raised by the hook -implementation - *) -let sender_hook_failed = "SENDER_HOOK_FAILED" -(** -Receiver hook is required by the permission behavior, but is not implemented by -a receiver contract - *) -let receiver_hook_undefined = "RECEIVER_HOOK_UNDEFINED" -(** -Sender hook is required by the permission behavior, but is not implemented by -a sender contract - *) -let sender_hook_undefined = "SENDER_HOOK_UNDEFINED" - -#endif diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/fa2_hook.mligo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/fa2_hook.mligo deleted file mode 100644 index 6137386..0000000 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/fa2_hook.mligo +++ /dev/null @@ -1,24 +0,0 @@ - -#if !FA2_HOOK -#define FA2_HOOK - -#include "fa2_interface.mligo" - - -type set_hook_param = { - hook : unit -> transfer_descriptor_param_michelson contract; - permissions_descriptor : permissions_descriptor; -} - -type set_hook_param_aux = { - hook : unit -> transfer_descriptor_param_michelson contract; - permissions_descriptor : permissions_descriptor_michelson; -} - -type set_hook_param_michelson = set_hook_param_aux michelson_pair_right_comb - -type fa2_with_hook_entry_points = - | Fa2 of fa2_entry_points - | Set_transfer_hook of set_hook_param_michelson - -#endif diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/fa2_interface.mligo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/fa2_interface.mligo deleted file mode 100644 index c6043a0..0000000 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/fa2_interface.mligo +++ /dev/null @@ -1,219 +0,0 @@ -#if ! FA2_INTERFACE -#define FA2_INTERFACE - -type token_id = nat - -type transfer_destination = { - to_ : address; - token_id : token_id; - amount : nat; -} - -type transfer_destination_michelson = transfer_destination michelson_pair_right_comb - -type transfer = { - from_ : address; - txs : transfer_destination list; -} - -type transfer_aux = { - from_ : address; - txs : transfer_destination_michelson list; -} - -type transfer_michelson = transfer_aux michelson_pair_right_comb - -type balance_of_request = { - owner : address; - token_id : token_id; -} - -type balance_of_request_michelson = balance_of_request michelson_pair_right_comb - -type balance_of_response = { - request : balance_of_request; - balance : nat; -} - -type balance_of_response_aux = { - request : balance_of_request_michelson; - balance : nat; -} - -type balance_of_response_michelson = balance_of_response_aux michelson_pair_right_comb - -type balance_of_param = { - requests : balance_of_request list; - callback : (balance_of_response_michelson list) contract; -} - -type balance_of_param_aux = { - requests : balance_of_request_michelson list; - callback : (balance_of_response_michelson list) contract; -} - -type balance_of_param_michelson = balance_of_param_aux michelson_pair_right_comb - -type total_supply_response = { - token_id : token_id; - total_supply : nat; -} - -type total_supply_response_michelson = total_supply_response michelson_pair_right_comb - -type total_supply_param = { - token_ids : token_id list; - callback : (total_supply_response_michelson list) contract; -} - -type total_supply_param_michelson = total_supply_param michelson_pair_right_comb - -type token_metadata = { - token_id : token_id; - symbol : string; - name : string; - decimals : nat; - extras : (string, string) map; -} - -type token_metadata_michelson = token_metadata michelson_pair_right_comb - -type token_metadata_param = { - token_ids : token_id list; - callback : (token_metadata_michelson list) contract; -} - -type token_metadata_param_michelson = token_metadata_param michelson_pair_right_comb - -type operator_param = { - owner : address; - operator : address; -} - -type operator_param_michelson = operator_param michelson_pair_right_comb - -type update_operator = - | Add_operator_p of operator_param - | Remove_operator_p of operator_param - -type update_operator_aux = - | Add_operator of operator_param_michelson - | Remove_operator of operator_param_michelson - -type update_operator_michelson = update_operator_aux michelson_or_right_comb - -type is_operator_response = { - operator : operator_param; - is_operator : bool; -} - -type is_operator_response_aux = { - operator : operator_param_michelson; - is_operator : bool; -} - -type is_operator_response_michelson = is_operator_response_aux michelson_pair_right_comb - -type is_operator_param = { - operator : operator_param; - callback : (is_operator_response_michelson) contract; -} - -type is_operator_param_aux = { - operator : operator_param_michelson; - callback : (is_operator_response_michelson) contract; -} - -type is_operator_param_michelson = is_operator_param_aux michelson_pair_right_comb - -(* permission policy definition *) - -type operator_transfer_policy = - | No_transfer - | Owner_transfer - | Owner_or_operator_transfer - -type operator_transfer_policy_michelson = operator_transfer_policy michelson_or_right_comb - -type owner_hook_policy = - | Owner_no_hook - | Optional_owner_hook - | Required_owner_hook - -type owner_hook_policy_michelson = owner_hook_policy michelson_or_right_comb - -type custom_permission_policy = { - tag : string; - config_api: address option; -} - -type custom_permission_policy_michelson = custom_permission_policy michelson_pair_right_comb - -type permissions_descriptor = { - operator : operator_transfer_policy; - receiver : owner_hook_policy; - sender : owner_hook_policy; - custom : custom_permission_policy option; -} - -type permissions_descriptor_aux = { - operator : operator_transfer_policy_michelson; - receiver : owner_hook_policy_michelson; - sender : owner_hook_policy_michelson; - custom : custom_permission_policy_michelson option; -} - -type permissions_descriptor_michelson = permissions_descriptor_aux michelson_pair_right_comb - -type fa2_entry_points = - | Transfer of transfer_michelson list - | Balance_of of balance_of_param_michelson - | Total_supply of total_supply_param_michelson - | Token_metadata of token_metadata_param_michelson - | Permissions_descriptor of permissions_descriptor_michelson contract - | Update_operators of update_operator_michelson list - | Is_operator of is_operator_param_michelson - - -type transfer_destination_descriptor = { - to_ : address option; - token_id : token_id; - amount : nat; -} - -type transfer_destination_descriptor_michelson = - transfer_destination_descriptor michelson_pair_right_comb - -type transfer_descriptor = { - from_ : address option; - txs : transfer_destination_descriptor list -} - -type transfer_descriptor_aux = { - from_ : address option; - txs : transfer_destination_descriptor_michelson list -} - -type transfer_descriptor_michelson = transfer_descriptor_aux michelson_pair_right_comb - -type transfer_descriptor_param = { - fa2 : address; - batch : transfer_descriptor list; - operator : address; -} - -type transfer_descriptor_param_aux = { - fa2 : address; - batch : transfer_descriptor_michelson list; - operator : address; -} - -type transfer_descriptor_param_michelson = transfer_descriptor_param_aux michelson_pair_right_comb - -type fa2_token_receiver = - | Tokens_received of transfer_descriptor_param_michelson - -type fa2_token_sender = - | Tokens_sent of transfer_descriptor_param_michelson - -#endif \ No newline at end of file diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/fa2_interface.religo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/fa2_interface.religo new file mode 100644 index 0000000..7de019d --- /dev/null +++ b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/fa2_interface.religo @@ -0,0 +1,149 @@ +#include "errors.religo" + +type tokenOperator = address; +type tokenOwner = address; +type tokenId = nat; +type tokenAmount = nat; +type tokenBalance = nat; + + +//////////////////////////// TRANSFER //////////////////////////////////////// +type transferContents = { + to_: tokenOwner, + token_id: tokenId, + amount: tokenAmount +}; + +type transfer = { + from_: tokenOwner, + txs: list(transferContents) +}; + +/** + * Concrete parameter type definitions with + * their Michelson representations. + */ +type transferContentsMichelson = michelson_pair_right_comb(transferContents); + +type transferAuxiliary = { + from_: tokenOwner, + txs: list(transferContentsMichelson) +}; + +type transferMichelson = michelson_pair_right_comb(transferAuxiliary); + +type transferParameter = list(transferMichelson); + + +///////////////////////////////////// BALANCEOF /////////////////////////////////// +type balanceOfRequest = { + owner: tokenOwner, + token_id: tokenId, +}; + +type balanceOfResponse = { + request: balanceOfRequest, + balance: tokenBalance, +}; + +type balanceOfCallback = contract(list(balanceOfResponse)); + +type balanceOfParameter = { + requests: list(balanceOfRequest), + callback: balanceOfCallback, +}; + +type balanceOfRequestMichelson = michelson_pair_right_comb(balanceOfRequest); + +type balanceOfResponseAuxiliary = { + request: balanceOfRequestMichelson, + balance: tokenBalance +}; + +type balanceOfResponseMichelson = michelson_pair_right_comb(balanceOfResponseAuxiliary); + +type balanceOfCallbackMichelson = contract(list(balanceOfResponseMichelson)); + +type balanceOfParameterAuxiliary = { + requests: list(balanceOfRequestMichelson), + callback: balanceOfCallbackMichelson +}; + +type balanceOfParameterMichelson = michelson_pair_right_comb(balanceOfParameterAuxiliary); + + +////////////// OPERATORS //////////// +type operatorParameter = { + owner: tokenOwner, + operator: tokenOperator, +} + +type updateOperatorsAddOrRemove = +// There's an extra `_p` in the constructors below to avoid 'redundant constructor' error +// due to the interop type conversions below +| Add_operator_p(operatorParameter) +| Remove_operator_p(operatorParameter) + +type operatorParameterMichelson = michelson_pair_right_comb(operatorParameter); + +type updateOperatorsAddOrRemoveAuxiliary = +| Add_operator(operatorParameterMichelson) +| Remove_operator(operatorParameterMichelson) + +type updateOperatorsAddOrRemoveMichelson = michelson_or_right_comb(updateOperatorsAddOrRemoveAuxiliary); + +type updateOperatorsParameter = list(updateOperatorsAddOrRemoveMichelson); + +///////////////////////// PERMISSIONS //////////////// +type operatorTransferPolicy = +| No_transfer +| Owner_transfer +| Owner_or_operator_transfer // default + +type ownerHookPolicy = +| Owner_no_hook // default +| Optional_owner_hook +| Required_owner_hook + +type customPermissionPolicy = { + tag: string, + config_api: option(address) +} + +type permissionsDescriptor = { + operator: operatorTransferPolicy, + receiver: ownerHookPolicy, + sender: ownerHookPolicy, + custom: option(customPermissionPolicy) +} + +// non-standard +type operatorUpdatePolicy = +| No_update +| Owner_update // default +| Owner_or_operator_update + +type operatorTransferPolicyMichelson = michelson_or_right_comb(operatorTransferPolicy); +type ownerHookPolicyMichelson = michelson_or_right_comb(ownerHookPolicy); +type customPermissionPolicyMichelson = michelson_pair_right_comb(customPermissionPolicy); + +type permissionsDescriptorAuxiliary = { + operator: operatorTransferPolicyMichelson, + receiver: ownerHookPolicyMichelson, + sender: ownerHookPolicyMichelson, + custom: option(customPermissionPolicyMichelson) +} + +type permissionsDescriptorMichelson = michelson_pair_right_comb(permissionsDescriptorAuxiliary); + +type permissionsDescriptorParameter = contract(permissionsDescriptorMichelson); + + + + +/////////////////////////////// ENTRYPOINTS /////////////////// +type parameter = +| Transfer(transferParameter) +| Balance_of(balanceOfParameterMichelson) +| Permissions_descriptor(permissionsDescriptorParameter) +| Update_operators(updateOperatorsParameter) \ No newline at end of file diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/lib/fa2_behaviors.mligo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/lib/fa2_behaviors.mligo deleted file mode 100644 index dd933ac..0000000 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/lib/fa2_behaviors.mligo +++ /dev/null @@ -1,87 +0,0 @@ -#if !FA2_BEHAVIORS -#define FA2_BEHAVIORS - -(* #include "fa2_hook_lib.mligo" *) -#include "../fa2_interface.mligo" -#include "../fa2_errors.mligo" - - -(** generic transfer hook implementation. Behavior is driven by `permissions_descriptor` *) - -type get_owners = transfer_descriptor -> (address option) list -type to_hook = address -> ((transfer_descriptor_param_michelson contract) option * string) -type transfer_hook_params = { - ligo_param : transfer_descriptor_param; - michelson_param : transfer_descriptor_param_michelson; -} - -let get_owners_from_batch (batch, get_owners : (transfer_descriptor list) * get_owners) : address set = - List.fold - (fun (acc, tx : (address set) * transfer_descriptor) -> - let owners = get_owners tx in - List.fold - (fun (acc, o: (address set) * (address option)) -> - match o with - | None -> acc - | Some a -> Set.add a acc - ) - owners - acc - ) - batch - (Set.empty : address set) - -let validate_owner_hook (p, get_owners, to_hook, is_required : - transfer_hook_params * get_owners * to_hook * bool) - : operation list = - let owners = get_owners_from_batch (p.ligo_param.batch, get_owners) in - Set.fold - (fun (ops, owner : (operation list) * address) -> - let hook, error = to_hook owner in - match hook with - | Some h -> - let op = Operation.transaction p.michelson_param 0mutez h in - op :: ops - | None -> - if is_required - then (failwith error : operation list) - else ops) - owners ([] : operation list) - -let validate_owner(p, policy, get_owners, to_hook : - transfer_hook_params * owner_hook_policy * get_owners * to_hook) - : operation list = - match policy with - | Owner_no_hook -> ([] : operation list) - | Optional_owner_hook -> validate_owner_hook (p, get_owners, to_hook, false) - | Required_owner_hook -> validate_owner_hook (p, get_owners, to_hook, true) - -let to_receiver_hook : to_hook = fun (a : address) -> - let c : (transfer_descriptor_param_michelson contract) option = - Operation.get_entrypoint_opt "%tokens_received" a in - c, receiver_hook_undefined - -let validate_receivers (p, policy : transfer_hook_params * owner_hook_policy) - : operation list = - let get_receivers : get_owners = fun (tx : transfer_descriptor) -> - List.map (fun (t : transfer_destination_descriptor) -> t.to_ )tx.txs in - validate_owner (p, policy, get_receivers, to_receiver_hook) - -let to_sender_hook : to_hook = fun (a : address) -> - let c : (transfer_descriptor_param_michelson contract) option = - Operation.get_entrypoint_opt "%tokens_sent" a in - c, sender_hook_undefined - -let validate_senders (p, policy : transfer_hook_params * owner_hook_policy) - : operation list = - let get_sender : get_owners = fun (tx : transfer_descriptor) -> [tx.from_] in - validate_owner (p, policy, get_sender, to_sender_hook) - -let standard_transfer_hook (p, descriptor : transfer_hook_params * permissions_descriptor) - : operation list = - let sender_ops = validate_senders (p, descriptor.sender) in - let receiver_ops = validate_receivers (p, descriptor.receiver) in - (* merge two lists *) - List.fold (fun (l, o : (operation list) * operation) -> o :: l) receiver_ops sender_ops - -#endif diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/lib/fa2_convertors.mligo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/lib/fa2_convertors.mligo deleted file mode 100644 index 9cc7c6c..0000000 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/lib/fa2_convertors.mligo +++ /dev/null @@ -1,187 +0,0 @@ -#if !FA2_CONVERTORS -#define FA2_CONVERTORS - -#include "../fa2_interface.mligo" - -let permissions_descriptor_to_michelson (d : permissions_descriptor) - : permissions_descriptor_michelson = - let aux : permissions_descriptor_aux = { - operator = Layout.convert_to_right_comb d.operator; - receiver = Layout.convert_to_right_comb d.receiver; - sender = Layout.convert_to_right_comb d.sender; - custom = match d.custom with - | None -> (None : custom_permission_policy_michelson option) - | Some c -> Some (Layout.convert_to_right_comb c) - } in - Layout.convert_to_right_comb aux - -let transfer_descriptor_to_michelson (p : transfer_descriptor) : transfer_descriptor_michelson = - let aux : transfer_descriptor_aux = { - from_ = p.from_; - txs = List.map - (fun (tx : transfer_destination_descriptor) -> - Layout.convert_to_right_comb tx - ) - p.txs; - } in - Layout.convert_to_right_comb aux - -let transfer_descriptor_param_to_michelson (p : transfer_descriptor_param) - : transfer_descriptor_param_michelson = - let aux : transfer_descriptor_param_aux = { - fa2 = p.fa2; - operator = p.operator; - batch = List.map - (fun (td: transfer_descriptor) -> transfer_descriptor_to_michelson td) - p.batch; - } in - Layout.convert_to_right_comb aux - -let transfer_descriptor_from_michelson (p : transfer_descriptor_michelson) : transfer_descriptor = - let aux : transfer_descriptor_aux = Layout.convert_from_right_comb p in - { - from_ = aux.from_; - txs = List.map - (fun (txm : transfer_destination_descriptor_michelson) -> - let tx : transfer_destination_descriptor = - Layout.convert_from_right_comb txm in - tx - ) - aux.txs; - } - -let transfer_descriptor_param_from_michelson (p : transfer_descriptor_param_michelson) - : transfer_descriptor_param = - let aux : transfer_descriptor_param_aux = Layout.convert_from_right_comb p in - let b : transfer_descriptor list = List.map - (fun (tdm : transfer_descriptor_michelson) -> - transfer_descriptor_from_michelson tdm - ) - aux.batch - in - { - fa2 = aux.fa2; - operator = aux.operator; - batch = b; - } - -let transfer_from_michelson (txm : transfer_michelson) : transfer = - let aux : transfer_aux = Layout.convert_from_right_comb txm in - { - from_ = aux.from_; - txs = List.map - (fun (txm : transfer_destination_michelson) -> - let tx : transfer_destination = Layout.convert_from_right_comb txm in - tx - ) - aux.txs; - } - -let transfers_from_michelson (txsm : transfer_michelson list) : transfer list = - List.map - (fun (txm: transfer_michelson) -> - let tx : transfer = transfer_from_michelson txm in - tx - ) txsm - -let operator_param_from_michelson (p : operator_param_michelson) : operator_param = - let op : operator_param = Layout.convert_from_right_comb p in - op - -let operator_param_to_michelson (p : operator_param) : operator_param_michelson = - Layout.convert_to_right_comb p - -let operator_update_from_michelson (uom : update_operator_michelson) : update_operator = - let aux : update_operator_aux = Layout.convert_from_right_comb uom in - match aux with - | Add_operator opm -> Add_operator_p (operator_param_from_michelson opm) - | Remove_operator opm -> Remove_operator_p (operator_param_from_michelson opm) - -let operator_update_to_michelson (uo : update_operator) : update_operator_michelson = - let aux = match uo with - | Add_operator_p op -> Add_operator (operator_param_to_michelson op) - | Remove_operator_p op -> Remove_operator (operator_param_to_michelson op) - in - Layout.convert_to_right_comb aux - -(* check this *) -let operator_updates_from_michelson (updates_michelson : update_operator_michelson list) - : update_operator list = - List.map operator_update_from_michelson updates_michelson - -let is_operator_param_from_michelson (p : is_operator_param_michelson) : is_operator_param = - let aux : is_operator_param_aux = Layout.convert_from_right_comb p in - { - operator = operator_param_from_michelson aux.operator; - callback = aux.callback; - } - -let is_operator_param_to_michelson (p : is_operator_param) : is_operator_param_michelson = - let aux : is_operator_param_aux = - { - operator = operator_param_to_michelson p.operator; - callback = p.callback; - } in - Layout.convert_to_right_comb aux - -let is_operator_response_to_michelson (r : is_operator_response) : is_operator_response_michelson = - let aux : is_operator_response_aux = { - operator = operator_param_to_michelson r.operator; - is_operator = r.is_operator; - } in - Layout.convert_to_right_comb aux - -let balance_of_param_from_michelson (p : balance_of_param_michelson) : balance_of_param = - let aux : balance_of_param_aux = Layout.convert_from_right_comb p in - let requests = List.map - (fun (rm : balance_of_request_michelson) -> - let r : balance_of_request = Layout.convert_from_right_comb rm in - r - ) - aux.requests - in - { - requests = requests; - callback = aux.callback; - } - -let balance_of_param_to_michelson (p : balance_of_param) : balance_of_param_michelson = - let aux : balance_of_param_aux = { - requests = List.map - (fun (r : balance_of_request) -> Layout.convert_to_right_comb r) - p.requests; - callback = p.callback; - } in - Layout.convert_to_right_comb aux - -let balance_of_response_to_michelson (r : balance_of_response) : balance_of_response_michelson = - let aux : balance_of_response_aux = { - request = Layout.convert_to_right_comb r.request; - balance = r.balance; - } in - Layout.convert_to_right_comb aux - -let balance_of_response_from_michelson (rm : balance_of_response_michelson) : balance_of_response = - let aux : balance_of_response_aux = Layout.convert_from_right_comb rm in - let request : balance_of_request = Layout.convert_from_right_comb aux.request in - { - request = request; - balance = aux.balance; - } - -let total_supply_responses_to_michelson (rs : total_supply_response list) - : total_supply_response_michelson list = - List.map - (fun (r : total_supply_response) -> - let rm : total_supply_response_michelson = Layout.convert_to_right_comb r in - rm - ) rs - -let token_metas_to_michelson (ms : token_metadata list) : token_metadata_michelson list = - List.map - ( fun (m : token_metadata) -> - let mm : token_metadata_michelson = Layout.convert_to_right_comb m in - mm - ) ms - -#endif \ No newline at end of file diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/lib/fa2_hook_lib.mligo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/lib/fa2_hook_lib.mligo deleted file mode 100644 index de1e3c1..0000000 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/lib/fa2_hook_lib.mligo +++ /dev/null @@ -1,40 +0,0 @@ -#if !FA2_HOOK_LIB -#define FA2_HOOK_LIB - -#include "../fa2_hook.mligo" -#include "fa2_convertors.mligo" - -let get_hook_entrypoint (hook_contract : address) (u : unit) - : transfer_descriptor_param_michelson contract = - let hook_entry : transfer_descriptor_param_michelson contract = - Operation.get_entrypoint "%tokens_transferred_hook" hook_contract in - hook_entry - - -let create_register_hook_op - (fa2, descriptor : (fa2_with_hook_entry_points contract) * permissions_descriptor) : operation = - let hook_fn = get_hook_entrypoint Current.self_address in - let p : set_hook_param_aux = { - hook = hook_fn; - permissions_descriptor = permissions_descriptor_to_michelson descriptor; - } in - let pm = Layout.convert_to_right_comb p in - Operation.transaction (Set_transfer_hook pm) 0mutez fa2 - - -type fa2_registry = address set - -let register_with_fa2 (fa2, descriptor, registry : - (fa2_with_hook_entry_points contract) * permissions_descriptor * fa2_registry) - : operation * fa2_registry = - let op = create_register_hook_op (fa2, descriptor) in - let fa2_address = Current.address fa2 in - let new_registry = Set.add fa2_address registry in - op, new_registry - -let validate_hook_call (fa2, registry: address * fa2_registry) : unit = - if Set.mem fa2 registry - then unit - else failwith "UNKNOWN_FA2_CALL" - -#endif diff --git a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/lib/fa2_operator_lib.mligo b/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/lib/fa2_operator_lib.mligo deleted file mode 100644 index 4872180..0000000 --- a/src/frontend/src/pages/Chapters/Reason/ChapterFA20/tzip-12/lib/fa2_operator_lib.mligo +++ /dev/null @@ -1,64 +0,0 @@ -(** Reference implementation of the FA2 operator storage and config API functions *) -#if !FA2_OPERATOR_LIB -#define FA2_OPERATOR_LIB - -#include "fa2_convertors.mligo" -#include "../fa2_errors.mligo" - -(* (owner, operator) -> unit *) -type operator_storage = ((address * address), unit) big_map - - -let update_operators (update, storage : update_operator * operator_storage) - : operator_storage = - match update with - | Add_operator_p op -> - Big_map.update (op.owner, op.operator) (Some unit) storage - | Remove_operator_p op -> - Big_map.remove (op.owner, op.operator) storage - -let validate_update_operators_by_owner (update, updater : update_operator * address) - : unit = - let op = match update with - | Add_operator_p op -> op - | Remove_operator_p op -> op - in - if op.owner = updater then unit else failwith not_owner - - -let is_operator (param, storage : is_operator_param * operator_storage) : operation = - let op_key = (param.operator.owner, param.operator.operator) in - let is_op = Big_map.mem op_key storage in - let r : is_operator_response = { - operator = param.operator; - is_operator = is_op; - } in - let rm = is_operator_response_to_michelson r in - Operation.transaction rm 0mutez param.callback - -let make_operator_validator (tx_policy : operator_transfer_policy) - : (address * operator_storage)-> unit = - let can_owner_tx, can_operator_tx = match tx_policy with - | No_transfer -> (failwith tx_denied : bool * bool) - | Owner_transfer -> true, false - | Owner_or_operator_transfer -> true, true - in - let operator : address = Tezos.sender in - (fun (owner, ops_storage : address * operator_storage) -> - if can_owner_tx && owner = operator - then unit - else - if not can_operator_tx - then failwith not_owner - else - if Big_map.mem (owner, operator) ops_storage - then unit else failwith not_operator - ) - -(** validate operators for all transfers in the batch at once*) -let validate_operator (tx_policy, txs, ops_storage - : operator_transfer_policy * (transfer list) * operator_storage) : unit = - let validator = make_operator_validator tx_policy in - List.iter (fun (tx : transfer) -> validator (tx.from_, ops_storage)) txs - -#endif