// Copyright Coase, Inc 2019 type card_pattern_id is nat type card_pattern is record [ coefficient : tez; quantity : nat ] type card_patterns is map (card_pattern_id, card_pattern) type card_id is nat type card is record [ card_owner : address; card_pattern : card_pattern_id ] type cards is map (card_id, card) type storage is record [ cards : cards; card_patterns : card_patterns; next_id : nat ] type return is list (operation) * storage type action_buy_single is record [ card_to_buy : card_pattern_id ] type action_sell_single is record [ card_to_sell : card_id ] type action_transfer_single is record [ card_to_transfer : card_id; destination : address ] type parameter is Buy_single of action_buy_single | Sell_single of action_sell_single | Transfer_single of action_transfer_single function transfer_single (const action : action_transfer_single; const s : storage) : return is block { const cards : cards = s.cards; const card : card = case cards[action.card_to_transfer] of Some (card) -> card | None -> (failwith ("transfer_single: No card.") : card) end; if card.card_owner =/= sender then failwith ("This card doesn't belong to you") else skip; card.card_owner := action.destination; cards[action.card_to_transfer] := card; s.cards := cards } with ((nil : list (operation)), s) function sell_single (const action : action_sell_single; const s : storage) : return is block { const card : card = case s.cards[action.card_to_sell] of Some (card) -> card | None -> (failwith ("sell_single: No card.") : card) end; if card.card_owner =/= sender then failwith ("This card doesn't belong to you") else skip; const card_pattern : card_pattern = case s.card_patterns[card.card_pattern] of Some (pattern) -> pattern | None -> (failwith ("sell_single: No card pattern.") : card_pattern) end; card_pattern.quantity := abs (card_pattern.quantity - 1n); const card_patterns : card_patterns = s.card_patterns; card_patterns[card.card_pattern] := card_pattern; s.card_patterns := card_patterns; const cards : cards = s.cards; remove action.card_to_sell from map cards; s.cards := cards; const price : tez = card_pattern.coefficient * card_pattern.quantity; const receiver : contract (unit) = case (Tezos.get_contract_opt (Tezos.sender) : option (contract (unit))) of Some (contract) -> contract | None -> (failwith ("sell_single: No contract.") : contract (unit)) end; const op : operation = Tezos.transaction (unit, price, receiver); const operations : list (operation) = list [op] } with (operations, s) function buy_single (const action : action_buy_single; const s : storage) : return is block { // Check funds const card_pattern : card_pattern = case s.card_patterns[action.card_to_buy] of Some (pattern) -> pattern | None -> (failwith ("buy_single: No card pattern.") : card_pattern) end; const price : tez = card_pattern.coefficient * (card_pattern.quantity + 1n); if price > amount then failwith ("Not enough money") else skip; // Increase quantity card_pattern.quantity := card_pattern.quantity + 1n; const card_patterns : card_patterns = s.card_patterns; card_patterns[action.card_to_buy] := card_pattern; s.card_patterns := card_patterns; // Add card const cards : cards = s.cards; cards[s.next_id] := record [ card_owner = sender; card_pattern = action.card_to_buy ]; s.cards := cards; s.next_id := s.next_id + 1n } with ((nil : list (operation)), s) function main (const action : parameter; const s : storage) : return is case action of Buy_single (bs) -> buy_single (bs, s) | Sell_single (as) -> sell_single (as, s) | Transfer_single (at) -> transfer_single (at, s) end