Commit 05ab17d6 authored by Eugene Mishura's avatar Eugene Mishura

strongly-typed config entry points WIP

parent 4454ce4c
Pipeline #115724759 passed with stage
in 2 minutes and 38 seconds
......@@ -11,38 +11,9 @@
#include "hook_lib.mligo"
type global_token_id = {
token_manager : address;
token_id : token_id;
}
type allowance_key = {
token_id : global_token_id;
owner : address;
spender : address;
}
type allowance_response = {
key: allowance_key;
allowance : nat;
}
type change_allowance_param = {
token_id : global_token_id;
spender : address;
prev_allowance : nat;
new_allowance : nat;
}
type view_allowance_param = {
key : allowance_key;
view : allowance_response contract;
}
type entry_points =
| Change_allowance of change_allowance_param
| View_allowance of view_allowance_param
| Allowances_config of fa2_allowances_config_entry_points
| Tokens_transferred_hook of hook_param
| Register_with_fa2 of fa2_entry_points contract
......@@ -50,22 +21,10 @@ type entry_points =
This will not work with babylon/LIGO since `allowance_key` is a composite
non-comparable record which cannot be used as a key in the big_map.
*)
type allowances = (allowance_key, nat) big_map
let get_allowance_key (operator : address) (owner : address)
(token_id : token_id) : allowance_key =
let tid : global_token_id = {
token_manager = Current.sender;
token_id = token_id;
} in
{
token_id = tid;
owner = owner;
spender = operator;
}
type allowances = (allowance_id, nat) big_map
let get_current_allowance (key : allowance_key) (a : allowances) : nat =
let a = Big_map.find_opt key a in
let get_current_allowance (id : allowance_id) (a : allowances) : nat =
let a = Big_map.find_opt id a in
match a with
| Some a -> a
| None -> 0n
......@@ -78,46 +37,68 @@ let track_allowances (operator : address) (a_tx : allowances * hook_transfer) :
if Current.self_address <> from_
then a
else
let akey = get_allowance_key operator from_ tx.token_id in
let allowance = get_current_allowance akey a in
let id : allowance_id = {
owner = from_;
token_id = tx.token_id;
token_manager = Current.sender;
spender = operator;
} in
let allowance = get_current_allowance id a in
let new_a = Michelson.is_nat (allowance - tx.amount) in
let new_allowance = match new_a with
| None -> (failwith "Insufficient allowance" : nat)
| Some a -> a
in
let new_a = Big_map.update akey (Some new_allowance) a in
let new_a = Big_map.update id (Some new_allowance) a in
new_a
let main (param, s : entry_points * allowances) : (operation list) * allowances =
let validate_owner (allowances : set_allowance_param list) : unit =
let owner = Current.self_address in
let u = List.iter (fun (a : set_allowance_param) ->
if a.allowance_id.owner = owner
then unit
else failwith "only owner can change its allowances"
) allowances in
unit
let config_allowances (param : fa2_allowances_config_entry_points) (s : allowances)
: (operation list) * allowances =
match param with
| Set_allowances ps ->
let u = validate_owner ps in
let new_s = List.fold (fun (a, cur : allowances * set_allowance_param ) ->
(* compare and swap *)
let allowance = get_current_allowance cur.allowance_id s in
if allowance <> cur.prev_allowance
then (failwith "cannot update allowance" : allowances)
else Big_map.update cur.allowance_id (Some cur.new_allowance) a
) ps s in
([] : operation list), new_s
| Change_allowance p ->
(* compare and swap *)
let key : allowance_key = {
token_id = p.token_id;
owner = Current.self_address;
spender = p.spender;
} in
let allowance = get_current_allowance key s in
if allowance <> p.prev_allowance
then (failwith "cannot update allowance" : (operation list) * allowances)
else
let new_s = Big_map.update key (Some p.new_allowance) s in
([] : operation list), new_s
| View_allowance p ->
let allowance = get_current_allowance p.key s in
let resp : allowance_response = {
key = p.key;
allowance = allowance;
} in
| Get_allowances p ->
let resp = List.map (fun (id : allowance_id) ->
let allowance = get_current_allowance id s in
let r : get_allowance_response = {
allowance_id = id;
allowance = allowance;
} in
r
) p.allowance_ids in
let op = Operation.transaction resp 0mutez p.view in
[op], s
let main (param, s : entry_points * allowances) : (operation list) * allowances =
match param with
| Allowances_config p -> config_allowances p s
| Tokens_transferred_hook p ->
let new_s = List.fold (track_allowances p.operator) p.batch s in
([] : operation list), new_s
| Register_with_fa2 fa2 ->
let op = create_register_hook_op fa2 (Some (Allowance_config Current.self_address)) in
let config_entrypoint : fa2_allowances_config_entry_points contract =
Operation.get_entrypoint "%allowances_config" Current.self_address in
let config = Allowances_config config_entrypoint in
let op = create_register_hook_op fa2 [config] in
[op], s
......@@ -26,5 +26,5 @@ type entry_points =
([] : operation list), unit
| Register_with_fa2 fa2 ->
let op = create_register_hook_op fa2 (None : permission_policy_config option) in
let op = create_register_hook_op fa2 ([] : permission_policy_config list) in
[op], s
\ No newline at end of file
......@@ -13,8 +13,7 @@
type entry_points =
| Add_operator of address
| Remove_operator of address
| Operators_config of fa2_operators_config_entry_points
| Tokens_transferred_hook of hook_param
| Register_with_fa2 of fa2_entry_points contract
......@@ -35,27 +34,60 @@ let is_allowed (owner : address) (operator : address) (operators : operators) :
then true
else false
let main (param, s : entry_points * operators) : (operation list) * operators =
let validate_owner_and_get_operators (owner : address) (ops : operator_param list)
(s : operators) : address set =
let u = List.iter (fun (op : operator_param) ->
if op.owner = owner
then unit
else failwith "only token owner can modify its operators") ops in
match Big_map.find_opt owner s with
| Some os -> os
| None -> (Set.empty : address set)
let config_operators (param : fa2_operators_config_entry_points) (s : operators)
: (operation list) * operators =
match param with
| Add_operator operator ->
| Add_operators p ->
let owner = Current.sender in
let ops = match Big_map.find_opt owner s with
| Some os -> os
| None -> (Set.empty : address set)
in
let new_ops = Set.add operator ops in
let ops = validate_owner_and_get_operators owner p s in
let new_ops = List.fold
(fun (so, cur : (address set) * operator_param)
-> Set.add cur.operator so)
p ops in
let new_s = Big_map.update owner (Some new_ops) s in
([] : operation list), new_s
([] : operation list), new_s
| Remove_operator operator ->
| Remove_operators p ->
let owner = Current.sender in
let ops = match Big_map.find_opt owner s with
| Some os -> os
| None -> (Set.empty : address set)
in
let new_ops = Set.remove operator ops in
let ops = validate_owner_and_get_operators owner p s in
let new_ops = List.fold
(fun (so, cur : (address set) * operator_param)
-> Set.remove cur.operator so)
p ops in
let new_s = Big_map.update owner (Some new_ops) s in
([] : operation list), new_s
([] : operation list), new_s
| Is_operator p ->
let r : is_operator_response list = List.map
(fun (op : operator_param) ->
let is_op = match Big_map.find_opt op.owner s with
| None -> false
| Some ops -> Set.mem op.operator ops
in
let resp : is_operator_response = {
operator = op;
is_operator = is_op;
} in
resp
)
p.operators in
let view_op = Operation.transaction r 0mutez p.view in
[view_op], s
(* ([] : operation list), s *)
let main (param, s : entry_points * operators) : (operation list) * operators =
match param with
| Operators_config oc -> config_operators oc s
| Tokens_transferred_hook p ->
let u = List.iter (fun (tx : hook_transfer) ->
......@@ -70,5 +102,8 @@ let main (param, s : entry_points * operators) : (operation list) * operators =
([] : operation list), s
| Register_with_fa2 fa2 ->
let op = create_register_hook_op fa2 (Some (Operator_config Current.self_address)) in
let config_entrypoint : fa2_operators_config_entry_points contract =
Operation.get_entrypoint "%operators_config" Current.self_address in
let config = Operators_config config_entrypoint in
let op = create_register_hook_op fa2 [config] in
[op], s
......@@ -12,23 +12,27 @@ MUST fail.
type entry_points =
| Add_receiver of address
| Remove_receiver of address
| Whitelist_config of fa2_whitelist_config_entry_points
| Tokens_transferred_hook of hook_param
| Register_with_fa2 of fa2_entry_points contract
type whitelist = address set
let main (param, s : entry_points * whitelist) : (operation list) * whitelist =
let config_whitelist (param : fa2_whitelist_config_entry_points) (s : whitelist)
: (operation list) * whitelist =
match param with
| Add_receiver op ->
let new_s = Set.add op s in
([] : operation list), new_s
| Add_to_white_list owners ->
let new_s = List.fold (fun (w, cur : whitelist * address) -> Set.add cur w) owners s in
([] : operation list), new_s
| Remove_from_white_list owners ->
let new_s = List.fold (fun (w, cur : whitelist * address) -> Set.remove cur w) owners s in
([] : operation list), new_s
| Remove_receiver op ->
let new_s = Set.remove op s in
([] : operation list), new_s
let main (param, s : entry_points * whitelist) : (operation list) * whitelist =
match param with
| Whitelist_config p -> config_whitelist p s
| Tokens_transferred_hook p ->
let u = List.iter (fun (tx : hook_transfer) ->
......@@ -43,5 +47,8 @@ let main (param, s : entry_points * whitelist) : (operation list) * whitelist =
([] : operation list), s
| Register_with_fa2 fa2 ->
let op = create_register_hook_op fa2 (Some (Whitelist_config Current.self_address)) in
let config_entrypoint : fa2_whitelist_config_entry_points contract =
Operation.get_entrypoint "%whitelist_config" Current.self_address in
let config = Whitelist_config config_entrypoint in
let op = create_register_hook_op fa2 [config] in
[op], s
......@@ -7,13 +7,10 @@ let get_hook (hook_contract : address) : address =
let create_register_hook_op
(fa2 : fa2_entry_points contract) (config : permission_policy_config option) : operation =
(fa2 : fa2_entry_points contract) (config : permission_policy_config list) : operation =
let hook : address = get_hook Current.self_address in
let cfg = match config with
| None -> ([] : permission_policy_config list)
| Some c -> [c] in
let pp : set_hook_param = {
hook = hook;
config = cfg;
config = config;
} in
Operation.transaction (Set_transfer_hook pp) 0mutez fa2
......@@ -11,17 +11,6 @@ type transfer = {
type transfer_param = transfer list
type custom_config_param = {
entrypoint : address;
tag : string;
}
type permission_policy_config =
| Allowance_config of address
| Operator_config of address
| Whitelist_config of address
| Custom_config of custom_config_param
type balance_request = {
owner : address;
token_id : token_id;
......@@ -76,21 +65,6 @@ type hook_param = {
operator : address;
}
type set_hook_param = {
hook : address;
config : permission_policy_config list;
}
type fa2_entry_points =
| Transfer of transfer_param
| Balance_of of balance_of_param
| Total_supply of total_supply_param
| Token_descriptor of token_descriptor_param
| Get_permissions_policy of permission_policy_config
(* Recommended design pattern. Not part of FA2 standard. *)
| Set_transfer_hook of set_hook_param
(** Different permissioning policy interfaces *)
(**
......@@ -114,11 +88,11 @@ type is_operator_response = {
}
type is_operator_param = {
operator : operator_param list;
operators : operator_param list;
view : (is_operator_response list) contract;
}
type fa2_operator_config_entry_points =
type fa2_operators_config_entry_points =
| Add_operators of operator_param list
| Remove_operators of operator_param list
| Is_operator of is_operator_param
......@@ -134,18 +108,17 @@ type fa2_operator_config_entry_points =
The owner does not need to be approved to transfer its own tokens.
*)
type set_allowance_param = {
type allowance_id = {
owner : address;
token_id : token_id;
token_manager : address;
spender : address;
prev_allowance : nat;
new_allowance : nat;
}
type allowance_id = {
owner : address;
token_id : token_id;
spender : address;
type set_allowance_param = {
allowance_id : allowance_id;
prev_allowance : nat;
new_allowance : nat;
}
type get_allowance_response = {
......@@ -158,9 +131,9 @@ type get_allowance_response = {
view : (get_allowance_response list) contract;
}
type fa2_allowance_config_entry_points =
| Set_allowance of set_allowance_param list
| Get_allowance of get_allowance_param
type fa2_allowances_config_entry_points =
| Set_allowances of set_allowance_param list
| Get_allowances of get_allowance_param
(**
......@@ -173,3 +146,28 @@ type get_allowance_response = {
type fa2_whitelist_config_entry_points =
| Add_to_white_list of address list
| Remove_from_white_list of address list
type custom_config_param = {
entrypoint : address;
tag : string;
}
type permission_policy_config =
| Allowances_config of (fa2_allowances_config_entry_points contract)
| Operators_config of (fa2_operators_config_entry_points contract)
| Whitelist_config of (fa2_whitelist_config_entry_points contract)
| Custom_config of custom_config_param
type set_hook_param = {
hook : address;
config : permission_policy_config list;
}
type fa2_entry_points =
| Transfer of transfer_param
| Balance_of of balance_of_param
| Total_supply of total_supply_param
| Token_descriptor of token_descriptor_param
| Get_permissions_policy of permission_policy_config
(* Recommended design pattern. Not part of FA2 standard. *)
| Set_transfer_hook of set_hook_param
\ No newline at end of file
......@@ -62,17 +62,6 @@ type transfer = {
type transfer_param = transfer list
type custom_config_param = {
entrypoint : address;
tag : string;
}
type permission_policy_config =
| Allowance_config of address
| Operator_config of address
| Whitelist_config of address
| Custom_config of custom_config_param
type balance_request = {
owner : address;
token_id : token_id;
......@@ -127,6 +116,17 @@ type hook_param = {
operator : address;
}
type custom_config_param = {
entrypoint : address;
tag : string;
}
type permission_policy_config =
| Allowances_config of (fa2_allowances_config_entry_points contract)
| Operators_config of (fa2_operators_config_entry_points contract)
| Whitelist_config of (fa2_whitelist_config_entry_points contract)
| Custom_config of custom_config_param
type set_hook_param = {
hook : address;
config : permission_policy_config list;
......@@ -174,18 +174,17 @@ The owner does not need to be approved to transfer its own tokens.
Config API provides the following entry points:
```ocaml
type set_allowance_param = {
type allowance_id = {
owner : address;
token_id : token_id;
token_manager : address;
spender : address;
prev_allowance : nat;
new_allowance : nat;
}
type allowance_id = {
owner : address;
token_id : token_id;
spender : address;
type set_allowance_param = {
allowance_id : allowance_id;
prev_allowance : nat;
new_allowance : nat;
}
type get_allowance_response = {
......@@ -198,9 +197,9 @@ type get_allowance_response = {
view : (get_allowance_response list) contract;
}
type fa2_allowance_config_entry_points =
| Set_allowance of set_allowance_param list
| Get_allowance of get_allowance_param
type fa2_allowances_config_entry_points =
| Set_allowances of set_allowance_param list
| Get_allowances of get_allowance_param
```
#### `operator_config`
......@@ -217,7 +216,7 @@ Config API provides the following entry points:
```ocaml
type operator_param = {
owner : address;
operator : address;
operator : address;
}
type is_operator_response = {
......@@ -226,11 +225,11 @@ type is_operator_response = {
}
type is_operator_param = {
operator : operator_param list;
operators : operator_param list;
view : (is_operator_response list) contract;
}
type fa2_operator_config_entry_points =
type fa2_operators_config_entry_points =
| Add_operators of operator_param list
| Remove_operators of operator_param list
| Is_operator of is_operator_param
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment