2019-09-05 17:21:01 +04:00
|
|
|
(*****************************************************************************)
|
|
|
|
(* *)
|
|
|
|
(* Open Source License *)
|
|
|
|
(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
|
|
|
(* *)
|
|
|
|
(* Permission is hereby granted, free of charge, to any person obtaining a *)
|
|
|
|
(* copy of this software and associated documentation files (the "Software"),*)
|
|
|
|
(* to deal in the Software without restriction, including without limitation *)
|
|
|
|
(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)
|
|
|
|
(* and/or sell copies of the Software, and to permit persons to whom the *)
|
|
|
|
(* Software is furnished to do so, subject to the following conditions: *)
|
|
|
|
(* *)
|
|
|
|
(* The above copyright notice and this permission notice shall be included *)
|
|
|
|
(* in all copies or substantial portions of the Software. *)
|
|
|
|
(* *)
|
|
|
|
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
|
|
|
|
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)
|
|
|
|
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)
|
|
|
|
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
|
|
|
|
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)
|
|
|
|
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)
|
|
|
|
(* DEALINGS IN THE SOFTWARE. *)
|
|
|
|
(* *)
|
|
|
|
(*****************************************************************************)
|
|
|
|
|
|
|
|
type balance =
|
|
|
|
| Contract of Contract_repr.t
|
|
|
|
| Rewards of Signature.Public_key_hash.t * Cycle_repr.t
|
|
|
|
| Fees of Signature.Public_key_hash.t * Cycle_repr.t
|
|
|
|
| Deposits of Signature.Public_key_hash.t * Cycle_repr.t
|
|
|
|
|
|
|
|
let balance_encoding =
|
|
|
|
let open Data_encoding in
|
2020-02-12 20:40:17 +04:00
|
|
|
def "operation_metadata.alpha.balance"
|
|
|
|
@@ union
|
|
|
|
[ case
|
|
|
|
(Tag 0)
|
|
|
|
~title:"Contract"
|
|
|
|
(obj2
|
|
|
|
(req "kind" (constant "contract"))
|
|
|
|
(req "contract" Contract_repr.encoding))
|
|
|
|
(function Contract c -> Some ((), c) | _ -> None)
|
|
|
|
(fun ((), c) -> Contract c);
|
|
|
|
case
|
|
|
|
(Tag 1)
|
|
|
|
~title:"Rewards"
|
|
|
|
(obj4
|
|
|
|
(req "kind" (constant "freezer"))
|
|
|
|
(req "category" (constant "rewards"))
|
|
|
|
(req "delegate" Signature.Public_key_hash.encoding)
|
|
|
|
(req "cycle" Cycle_repr.encoding))
|
|
|
|
(function Rewards (d, l) -> Some ((), (), d, l) | _ -> None)
|
|
|
|
(fun ((), (), d, l) -> Rewards (d, l));
|
|
|
|
case
|
|
|
|
(Tag 2)
|
|
|
|
~title:"Fees"
|
|
|
|
(obj4
|
|
|
|
(req "kind" (constant "freezer"))
|
|
|
|
(req "category" (constant "fees"))
|
|
|
|
(req "delegate" Signature.Public_key_hash.encoding)
|
|
|
|
(req "cycle" Cycle_repr.encoding))
|
|
|
|
(function Fees (d, l) -> Some ((), (), d, l) | _ -> None)
|
|
|
|
(fun ((), (), d, l) -> Fees (d, l));
|
|
|
|
case
|
|
|
|
(Tag 3)
|
|
|
|
~title:"Deposits"
|
|
|
|
(obj4
|
|
|
|
(req "kind" (constant "freezer"))
|
|
|
|
(req "category" (constant "deposits"))
|
|
|
|
(req "delegate" Signature.Public_key_hash.encoding)
|
|
|
|
(req "cycle" Cycle_repr.encoding))
|
|
|
|
(function Deposits (d, l) -> Some ((), (), d, l) | _ -> None)
|
|
|
|
(fun ((), (), d, l) -> Deposits (d, l)) ]
|
|
|
|
|
|
|
|
type balance_update = Debited of Tez_repr.t | Credited of Tez_repr.t
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let balance_update_encoding =
|
|
|
|
let open Data_encoding in
|
2020-02-12 20:40:17 +04:00
|
|
|
def "operation_metadata.alpha.balance_update"
|
|
|
|
@@ obj1
|
|
|
|
(req
|
|
|
|
"change"
|
|
|
|
(conv
|
|
|
|
(function
|
|
|
|
| Credited v ->
|
|
|
|
Tez_repr.to_mutez v
|
|
|
|
| Debited v ->
|
|
|
|
Int64.neg (Tez_repr.to_mutez v))
|
|
|
|
( Json.wrap_error
|
|
|
|
@@ fun v ->
|
|
|
|
if Compare.Int64.(v < 0L) then
|
|
|
|
match Tez_repr.of_mutez (Int64.neg v) with
|
|
|
|
| Some v ->
|
|
|
|
Debited v
|
|
|
|
| None ->
|
|
|
|
failwith "Qty.of_mutez"
|
|
|
|
else
|
|
|
|
match Tez_repr.of_mutez v with
|
|
|
|
| Some v ->
|
|
|
|
Credited v
|
|
|
|
| None ->
|
|
|
|
failwith "Qty.of_mutez" )
|
|
|
|
int64))
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
type balance_updates = (balance * balance_update) list
|
|
|
|
|
|
|
|
let balance_updates_encoding =
|
|
|
|
let open Data_encoding in
|
2020-02-12 20:40:17 +04:00
|
|
|
def "operation_metadata.alpha.balance_updates"
|
|
|
|
@@ list (merge_objs balance_encoding balance_update_encoding)
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let cleanup_balance_updates balance_updates =
|
|
|
|
List.filter
|
|
|
|
(fun (_, (Credited update | Debited update)) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
not (Tez_repr.equal update Tez_repr.zero))
|
2019-09-05 17:21:01 +04:00
|
|
|
balance_updates
|
|
|
|
|
|
|
|
type frozen_balance = {
|
2020-02-12 20:40:17 +04:00
|
|
|
deposit : Tez_repr.t;
|
|
|
|
fees : Tez_repr.t;
|
|
|
|
rewards : Tez_repr.t;
|
2019-09-05 17:21:01 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
let frozen_balance_encoding =
|
|
|
|
let open Data_encoding in
|
|
|
|
conv
|
2020-02-12 20:40:17 +04:00
|
|
|
(fun {deposit; fees; rewards} -> (deposit, fees, rewards))
|
|
|
|
(fun (deposit, fees, rewards) -> {deposit; fees; rewards})
|
2019-09-05 17:21:01 +04:00
|
|
|
(obj3
|
|
|
|
(req "deposit" Tez_repr.encoding)
|
|
|
|
(req "fees" Tez_repr.encoding)
|
|
|
|
(req "rewards" Tez_repr.encoding))
|
|
|
|
|
|
|
|
type error +=
|
|
|
|
| No_deletion of Signature.Public_key_hash.t (* `Permanent *)
|
|
|
|
| Active_delegate (* `Temporary *)
|
|
|
|
| Current_delegate (* `Temporary *)
|
|
|
|
| Empty_delegate_account of Signature.Public_key_hash.t (* `Temporary *)
|
2020-02-12 20:40:17 +04:00
|
|
|
| Balance_too_low_for_deposit of {
|
|
|
|
delegate : Signature.Public_key_hash.t;
|
|
|
|
deposit : Tez_repr.t;
|
|
|
|
balance : Tez_repr.t;
|
|
|
|
}
|
|
|
|
|
|
|
|
(* `Temporary *)
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let () =
|
|
|
|
register_error_kind
|
|
|
|
`Permanent
|
|
|
|
~id:"delegate.no_deletion"
|
|
|
|
~title:"Forbidden delegate deletion"
|
|
|
|
~description:"Tried to unregister a delegate"
|
|
|
|
~pp:(fun ppf delegate ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"Delegate deletion is forbidden (%a)"
|
|
|
|
Signature.Public_key_hash.pp
|
|
|
|
delegate)
|
2019-09-05 17:21:01 +04:00
|
|
|
Data_encoding.(obj1 (req "delegate" Signature.Public_key_hash.encoding))
|
|
|
|
(function No_deletion c -> Some c | _ -> None)
|
|
|
|
(fun c -> No_deletion c) ;
|
|
|
|
register_error_kind
|
|
|
|
`Temporary
|
|
|
|
~id:"delegate.already_active"
|
|
|
|
~title:"Delegate already active"
|
|
|
|
~description:"Useless delegate reactivation"
|
|
|
|
~pp:(fun ppf () ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf ppf "The delegate is still active, no need to refresh it")
|
2019-09-05 17:21:01 +04:00
|
|
|
Data_encoding.empty
|
|
|
|
(function Active_delegate -> Some () | _ -> None)
|
|
|
|
(fun () -> Active_delegate) ;
|
|
|
|
register_error_kind
|
|
|
|
`Temporary
|
|
|
|
~id:"delegate.unchanged"
|
|
|
|
~title:"Unchanged delegated"
|
|
|
|
~description:"Contract already delegated to the given delegate"
|
|
|
|
~pp:(fun ppf () ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"The contract is already delegated to the same delegate")
|
2019-09-05 17:21:01 +04:00
|
|
|
Data_encoding.empty
|
|
|
|
(function Current_delegate -> Some () | _ -> None)
|
|
|
|
(fun () -> Current_delegate) ;
|
|
|
|
register_error_kind
|
|
|
|
`Permanent
|
|
|
|
~id:"delegate.empty_delegate_account"
|
|
|
|
~title:"Empty delegate account"
|
2020-02-12 20:40:17 +04:00
|
|
|
~description:
|
|
|
|
"Cannot register a delegate when its implicit account is empty"
|
2019-09-05 17:21:01 +04:00
|
|
|
~pp:(fun ppf delegate ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"Delegate registration is forbidden when the delegate\n\
|
|
|
|
\ implicit account is empty (%a)"
|
|
|
|
Signature.Public_key_hash.pp
|
|
|
|
delegate)
|
2019-09-05 17:21:01 +04:00
|
|
|
Data_encoding.(obj1 (req "delegate" Signature.Public_key_hash.encoding))
|
|
|
|
(function Empty_delegate_account c -> Some c | _ -> None)
|
|
|
|
(fun c -> Empty_delegate_account c) ;
|
|
|
|
register_error_kind
|
|
|
|
`Temporary
|
|
|
|
~id:"delegate.balance_too_low_for_deposit"
|
|
|
|
~title:"Balance too low for deposit"
|
|
|
|
~description:"Cannot freeze deposit when the balance is too low"
|
|
|
|
~pp:(fun ppf (delegate, balance, deposit) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"Delegate %a has a too low balance (%a) to deposit %a"
|
|
|
|
Signature.Public_key_hash.pp
|
|
|
|
delegate
|
|
|
|
Tez_repr.pp
|
|
|
|
balance
|
|
|
|
Tez_repr.pp
|
|
|
|
deposit)
|
|
|
|
Data_encoding.(
|
|
|
|
obj3
|
|
|
|
(req "delegate" Signature.Public_key_hash.encoding)
|
|
|
|
(req "balance" Tez_repr.encoding)
|
|
|
|
(req "deposit" Tez_repr.encoding))
|
|
|
|
(function
|
|
|
|
| Balance_too_low_for_deposit {delegate; balance; deposit} ->
|
|
|
|
Some (delegate, balance, deposit)
|
|
|
|
| _ ->
|
|
|
|
None)
|
|
|
|
(fun (delegate, balance, deposit) ->
|
|
|
|
Balance_too_low_for_deposit {delegate; balance; deposit})
|
2019-09-05 17:21:01 +04:00
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
let link c contract delegate =
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Balance.get c contract
|
|
|
|
>>=? fun balance ->
|
|
|
|
Roll_storage.Delegate.add_amount c delegate balance
|
|
|
|
>>=? fun c ->
|
|
|
|
Storage.Contract.Delegated.add
|
|
|
|
(c, Contract_repr.implicit_contract delegate)
|
|
|
|
contract
|
|
|
|
>>= fun c -> return c
|
2019-09-05 17:21:01 +04:00
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
let unlink c contract =
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Balance.get c contract
|
|
|
|
>>=? fun balance ->
|
|
|
|
Storage.Contract.Delegate.get_option c contract
|
|
|
|
>>=? function
|
|
|
|
| None ->
|
|
|
|
return c
|
2019-09-05 17:21:01 +04:00
|
|
|
| Some delegate ->
|
2019-10-17 13:45:27 +04:00
|
|
|
(* Removes the balance of the contract from the delegate *)
|
2020-02-12 20:40:17 +04:00
|
|
|
Roll_storage.Delegate.remove_amount c delegate balance
|
|
|
|
>>=? fun c ->
|
|
|
|
Storage.Contract.Delegated.del
|
|
|
|
(c, Contract_repr.implicit_contract delegate)
|
|
|
|
contract
|
|
|
|
>>= fun c -> return c
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let known c delegate =
|
|
|
|
Storage.Contract.Manager.get_option
|
2020-02-12 20:40:17 +04:00
|
|
|
c
|
|
|
|
(Contract_repr.implicit_contract delegate)
|
|
|
|
>>=? function
|
|
|
|
| None | Some (Manager_repr.Hash _) ->
|
|
|
|
return_false
|
|
|
|
| Some (Manager_repr.Public_key _) ->
|
|
|
|
return_true
|
2019-09-05 17:21:01 +04:00
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
(* A delegate is registered if its "implicit account" delegates to itself. *)
|
2019-09-05 17:21:01 +04:00
|
|
|
let registered c delegate =
|
2019-10-17 13:45:27 +04:00
|
|
|
Storage.Contract.Delegate.get_option
|
2020-02-12 20:40:17 +04:00
|
|
|
c
|
|
|
|
(Contract_repr.implicit_contract delegate)
|
|
|
|
>>=? function
|
2019-10-17 13:45:27 +04:00
|
|
|
| Some current_delegate ->
|
|
|
|
return @@ Signature.Public_key_hash.equal delegate current_delegate
|
|
|
|
| None ->
|
|
|
|
return_false
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let init ctxt contract delegate =
|
2020-02-12 20:40:17 +04:00
|
|
|
known ctxt delegate
|
|
|
|
>>=? fun known_delegate ->
|
|
|
|
fail_unless known_delegate (Roll_storage.Unregistered_delegate delegate)
|
|
|
|
>>=? fun () ->
|
|
|
|
registered ctxt delegate
|
|
|
|
>>=? fun is_registered ->
|
|
|
|
fail_unless is_registered (Roll_storage.Unregistered_delegate delegate)
|
|
|
|
>>=? fun () ->
|
|
|
|
Storage.Contract.Delegate.init ctxt contract delegate
|
|
|
|
>>=? fun ctxt -> link ctxt contract delegate
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let get = Roll_storage.get_contract_delegate
|
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
let set c contract delegate =
|
2019-09-05 17:21:01 +04:00
|
|
|
match delegate with
|
2020-02-12 20:40:17 +04:00
|
|
|
| None -> (
|
2019-10-17 13:45:27 +04:00
|
|
|
let delete () =
|
2020-02-12 20:40:17 +04:00
|
|
|
unlink c contract
|
|
|
|
>>=? fun c ->
|
|
|
|
Storage.Contract.Delegate.remove c contract >>= fun c -> return c
|
|
|
|
in
|
2019-09-05 17:21:01 +04:00
|
|
|
match Contract_repr.is_implicit contract with
|
|
|
|
| Some pkh ->
|
2019-10-17 13:45:27 +04:00
|
|
|
(* check if contract is a registered delegate *)
|
2020-02-12 20:40:17 +04:00
|
|
|
registered c pkh
|
|
|
|
>>=? fun is_registered ->
|
|
|
|
if is_registered then fail (No_deletion pkh) else delete ()
|
|
|
|
| None ->
|
|
|
|
delete () )
|
2019-09-05 17:21:01 +04:00
|
|
|
| Some delegate ->
|
2020-02-12 20:40:17 +04:00
|
|
|
known c delegate
|
|
|
|
>>=? fun known_delegate ->
|
|
|
|
registered c delegate
|
|
|
|
>>=? fun registered_delegate ->
|
2019-09-05 17:21:01 +04:00
|
|
|
let self_delegation =
|
|
|
|
match Contract_repr.is_implicit contract with
|
2020-02-12 20:40:17 +04:00
|
|
|
| Some pkh ->
|
|
|
|
Signature.Public_key_hash.equal pkh delegate
|
|
|
|
| None ->
|
|
|
|
false
|
|
|
|
in
|
|
|
|
if (not known_delegate) || not (registered_delegate || self_delegation)
|
|
|
|
then fail (Roll_storage.Unregistered_delegate delegate)
|
2019-09-05 17:21:01 +04:00
|
|
|
else
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Delegate.get_option c contract
|
|
|
|
>>=? (function
|
|
|
|
| Some current_delegate
|
|
|
|
when Signature.Public_key_hash.equal delegate current_delegate
|
|
|
|
->
|
|
|
|
if self_delegation then
|
|
|
|
Roll_storage.Delegate.is_inactive c delegate
|
|
|
|
>>=? function
|
|
|
|
| true -> return_unit | false -> fail Active_delegate
|
|
|
|
else fail Current_delegate
|
|
|
|
| None | Some _ ->
|
|
|
|
return_unit)
|
|
|
|
>>=? fun () ->
|
2019-10-17 13:45:27 +04:00
|
|
|
(* check if contract is a registered delegate *)
|
2020-02-12 20:40:17 +04:00
|
|
|
( match Contract_repr.is_implicit contract with
|
|
|
|
| Some pkh ->
|
|
|
|
registered c pkh
|
|
|
|
>>=? fun is_registered ->
|
|
|
|
(* allow self-delegation to re-activate *)
|
|
|
|
if (not self_delegation) && is_registered then
|
|
|
|
fail (No_deletion pkh)
|
|
|
|
else return_unit
|
|
|
|
| None ->
|
|
|
|
return_unit )
|
|
|
|
>>=? fun () ->
|
|
|
|
Storage.Contract.Balance.mem c contract
|
|
|
|
>>= fun exists ->
|
2019-09-05 17:21:01 +04:00
|
|
|
fail_when
|
|
|
|
(self_delegation && not exists)
|
2020-02-12 20:40:17 +04:00
|
|
|
(Empty_delegate_account delegate)
|
|
|
|
>>=? fun () ->
|
|
|
|
unlink c contract
|
|
|
|
>>=? fun c ->
|
|
|
|
Storage.Contract.Delegate.init_set c contract delegate
|
|
|
|
>>= fun c ->
|
|
|
|
link c contract delegate
|
|
|
|
>>=? fun c ->
|
|
|
|
( if self_delegation then
|
|
|
|
Storage.Delegates.add c delegate
|
|
|
|
>>= fun c ->
|
|
|
|
Roll_storage.Delegate.set_active c delegate >>=? fun c -> return c
|
|
|
|
else return c )
|
|
|
|
>>=? fun c -> return c
|
|
|
|
|
|
|
|
let remove ctxt contract = unlink ctxt contract
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let delegated_contracts ctxt delegate =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
|
|
|
Storage.Contract.Delegated.elements (ctxt, contract)
|
|
|
|
|
|
|
|
let get_frozen_deposit ctxt contract cycle =
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Frozen_deposits.get_option (ctxt, contract) cycle
|
|
|
|
>>=? function None -> return Tez_repr.zero | Some frozen -> return frozen
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let credit_frozen_deposit ctxt delegate cycle amount =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
2020-02-12 20:40:17 +04:00
|
|
|
get_frozen_deposit ctxt contract cycle
|
|
|
|
>>=? fun old_amount ->
|
|
|
|
Lwt.return Tez_repr.(old_amount +? amount)
|
|
|
|
>>=? fun new_amount ->
|
|
|
|
Storage.Contract.Frozen_deposits.init_set (ctxt, contract) cycle new_amount
|
|
|
|
>>= fun ctxt ->
|
|
|
|
Storage.Delegates_with_frozen_balance.add (ctxt, cycle) delegate
|
|
|
|
>>= fun ctxt -> return ctxt
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let freeze_deposit ctxt delegate amount =
|
2020-02-12 20:40:17 +04:00
|
|
|
let {Level_repr.cycle; _} = Level_storage.current ctxt in
|
|
|
|
Roll_storage.Delegate.set_active ctxt delegate
|
|
|
|
>>=? fun ctxt ->
|
2019-09-05 17:21:01 +04:00
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Balance.get ctxt contract
|
|
|
|
>>=? fun balance ->
|
2019-09-05 17:21:01 +04:00
|
|
|
Lwt.return
|
2020-02-12 20:40:17 +04:00
|
|
|
(record_trace
|
|
|
|
(Balance_too_low_for_deposit {delegate; deposit = amount; balance})
|
|
|
|
Tez_repr.(balance -? amount))
|
|
|
|
>>=? fun new_balance ->
|
|
|
|
Storage.Contract.Balance.set ctxt contract new_balance
|
|
|
|
>>=? fun ctxt -> credit_frozen_deposit ctxt delegate cycle amount
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let get_frozen_fees ctxt contract cycle =
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Frozen_fees.get_option (ctxt, contract) cycle
|
|
|
|
>>=? function None -> return Tez_repr.zero | Some frozen -> return frozen
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let credit_frozen_fees ctxt delegate cycle amount =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
2020-02-12 20:40:17 +04:00
|
|
|
get_frozen_fees ctxt contract cycle
|
|
|
|
>>=? fun old_amount ->
|
|
|
|
Lwt.return Tez_repr.(old_amount +? amount)
|
|
|
|
>>=? fun new_amount ->
|
|
|
|
Storage.Contract.Frozen_fees.init_set (ctxt, contract) cycle new_amount
|
|
|
|
>>= fun ctxt ->
|
|
|
|
Storage.Delegates_with_frozen_balance.add (ctxt, cycle) delegate
|
|
|
|
>>= fun ctxt -> return ctxt
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let freeze_fees ctxt delegate amount =
|
2020-02-12 20:40:17 +04:00
|
|
|
let {Level_repr.cycle; _} = Level_storage.current ctxt in
|
|
|
|
Roll_storage.Delegate.add_amount ctxt delegate amount
|
|
|
|
>>=? fun ctxt -> credit_frozen_fees ctxt delegate cycle amount
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let burn_fees ctxt delegate cycle amount =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
2020-02-12 20:40:17 +04:00
|
|
|
get_frozen_fees ctxt contract cycle
|
|
|
|
>>=? fun old_amount ->
|
|
|
|
( match Tez_repr.(old_amount -? amount) with
|
|
|
|
| Ok new_amount ->
|
|
|
|
Roll_storage.Delegate.remove_amount ctxt delegate amount
|
|
|
|
>>=? fun ctxt -> return (new_amount, ctxt)
|
|
|
|
| Error _ ->
|
|
|
|
Roll_storage.Delegate.remove_amount ctxt delegate old_amount
|
|
|
|
>>=? fun ctxt -> return (Tez_repr.zero, ctxt) )
|
|
|
|
>>=? fun (new_amount, ctxt) ->
|
|
|
|
Storage.Contract.Frozen_fees.init_set (ctxt, contract) cycle new_amount
|
|
|
|
>>= fun ctxt -> return ctxt
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let get_frozen_rewards ctxt contract cycle =
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Frozen_rewards.get_option (ctxt, contract) cycle
|
|
|
|
>>=? function None -> return Tez_repr.zero | Some frozen -> return frozen
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let credit_frozen_rewards ctxt delegate cycle amount =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
2020-02-12 20:40:17 +04:00
|
|
|
get_frozen_rewards ctxt contract cycle
|
|
|
|
>>=? fun old_amount ->
|
|
|
|
Lwt.return Tez_repr.(old_amount +? amount)
|
|
|
|
>>=? fun new_amount ->
|
|
|
|
Storage.Contract.Frozen_rewards.init_set (ctxt, contract) cycle new_amount
|
|
|
|
>>= fun ctxt ->
|
|
|
|
Storage.Delegates_with_frozen_balance.add (ctxt, cycle) delegate
|
|
|
|
>>= fun ctxt -> return ctxt
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let freeze_rewards ctxt delegate amount =
|
2020-02-12 20:40:17 +04:00
|
|
|
let {Level_repr.cycle; _} = Level_storage.current ctxt in
|
2019-09-05 17:21:01 +04:00
|
|
|
credit_frozen_rewards ctxt delegate cycle amount
|
|
|
|
|
|
|
|
let burn_rewards ctxt delegate cycle amount =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
2020-02-12 20:40:17 +04:00
|
|
|
get_frozen_rewards ctxt contract cycle
|
|
|
|
>>=? fun old_amount ->
|
2019-09-05 17:21:01 +04:00
|
|
|
let new_amount =
|
|
|
|
match Tez_repr.(old_amount -? amount) with
|
2020-02-12 20:40:17 +04:00
|
|
|
| Error _ ->
|
|
|
|
Tez_repr.zero
|
|
|
|
| Ok new_amount ->
|
|
|
|
new_amount
|
|
|
|
in
|
|
|
|
Storage.Contract.Frozen_rewards.init_set (ctxt, contract) cycle new_amount
|
|
|
|
>>= fun ctxt -> return ctxt
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let unfreeze ctxt delegate cycle =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
2020-02-12 20:40:17 +04:00
|
|
|
get_frozen_deposit ctxt contract cycle
|
|
|
|
>>=? fun deposit ->
|
|
|
|
get_frozen_fees ctxt contract cycle
|
|
|
|
>>=? fun fees ->
|
|
|
|
get_frozen_rewards ctxt contract cycle
|
|
|
|
>>=? fun rewards ->
|
|
|
|
Storage.Contract.Balance.get ctxt contract
|
|
|
|
>>=? fun balance ->
|
|
|
|
Lwt.return Tez_repr.(deposit +? fees)
|
|
|
|
>>=? fun unfrozen_amount ->
|
|
|
|
Lwt.return Tez_repr.(unfrozen_amount +? rewards)
|
|
|
|
>>=? fun unfrozen_amount ->
|
|
|
|
Lwt.return Tez_repr.(balance +? unfrozen_amount)
|
|
|
|
>>=? fun balance ->
|
|
|
|
Storage.Contract.Balance.set ctxt contract balance
|
|
|
|
>>=? fun ctxt ->
|
|
|
|
Roll_storage.Delegate.add_amount ctxt delegate rewards
|
|
|
|
>>=? fun ctxt ->
|
|
|
|
Storage.Contract.Frozen_deposits.remove (ctxt, contract) cycle
|
|
|
|
>>= fun ctxt ->
|
|
|
|
Storage.Contract.Frozen_fees.remove (ctxt, contract) cycle
|
|
|
|
>>= fun ctxt ->
|
|
|
|
Storage.Contract.Frozen_rewards.remove (ctxt, contract) cycle
|
|
|
|
>>= fun ctxt ->
|
|
|
|
return
|
|
|
|
( ctxt,
|
|
|
|
cleanup_balance_updates
|
|
|
|
[ (Deposits (delegate, cycle), Debited deposit);
|
|
|
|
(Fees (delegate, cycle), Debited fees);
|
|
|
|
(Rewards (delegate, cycle), Debited rewards);
|
|
|
|
( Contract (Contract_repr.implicit_contract delegate),
|
|
|
|
Credited unfrozen_amount ) ] )
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let cycle_end ctxt last_cycle unrevealed =
|
|
|
|
let preserved = Constants_storage.preserved_cycles ctxt in
|
2020-02-12 20:40:17 +04:00
|
|
|
( match Cycle_repr.pred last_cycle with
|
|
|
|
| None ->
|
|
|
|
return (ctxt, [])
|
|
|
|
| Some revealed_cycle ->
|
|
|
|
List.fold_left
|
|
|
|
(fun acc (u : Nonce_storage.unrevealed) ->
|
|
|
|
acc
|
|
|
|
>>=? fun (ctxt, balance_updates) ->
|
|
|
|
burn_fees ctxt u.delegate revealed_cycle u.fees
|
|
|
|
>>=? fun ctxt ->
|
|
|
|
burn_rewards ctxt u.delegate revealed_cycle u.rewards
|
|
|
|
>>=? fun ctxt ->
|
|
|
|
let bus =
|
|
|
|
[ (Fees (u.delegate, revealed_cycle), Debited u.fees);
|
|
|
|
(Rewards (u.delegate, revealed_cycle), Debited u.rewards) ]
|
|
|
|
in
|
|
|
|
return (ctxt, bus @ balance_updates))
|
|
|
|
(return (ctxt, []))
|
|
|
|
unrevealed )
|
|
|
|
>>=? fun (ctxt, balance_updates) ->
|
2019-09-05 17:21:01 +04:00
|
|
|
match Cycle_repr.sub last_cycle preserved with
|
2020-02-12 20:40:17 +04:00
|
|
|
| None ->
|
|
|
|
return (ctxt, balance_updates, [])
|
2019-09-05 17:21:01 +04:00
|
|
|
| Some unfrozen_cycle ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Delegates_with_frozen_balance.fold
|
|
|
|
(ctxt, unfrozen_cycle)
|
2019-09-05 17:21:01 +04:00
|
|
|
~init:(Ok (ctxt, balance_updates))
|
|
|
|
~f:(fun delegate acc ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Lwt.return acc
|
|
|
|
>>=? fun (ctxt, bus) ->
|
|
|
|
unfreeze ctxt delegate unfrozen_cycle
|
|
|
|
>>=? fun (ctxt, balance_updates) ->
|
|
|
|
return (ctxt, balance_updates @ bus))
|
|
|
|
>>=? fun (ctxt, balance_updates) ->
|
|
|
|
Storage.Delegates_with_frozen_balance.clear (ctxt, unfrozen_cycle)
|
|
|
|
>>= fun ctxt ->
|
|
|
|
Storage.Active_delegates_with_rolls.fold
|
|
|
|
ctxt
|
2019-09-05 17:21:01 +04:00
|
|
|
~init:(Ok (ctxt, []))
|
|
|
|
~f:(fun delegate acc ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Lwt.return acc
|
|
|
|
>>=? fun (ctxt, deactivated) ->
|
|
|
|
Storage.Contract.Delegate_desactivation.get
|
|
|
|
ctxt
|
|
|
|
(Contract_repr.implicit_contract delegate)
|
|
|
|
>>=? fun cycle ->
|
|
|
|
if Cycle_repr.(cycle <= last_cycle) then
|
|
|
|
Roll_storage.Delegate.set_inactive ctxt delegate
|
|
|
|
>>=? fun ctxt -> return (ctxt, delegate :: deactivated)
|
|
|
|
else return (ctxt, deactivated))
|
|
|
|
>>=? fun (ctxt, deactivated) ->
|
2019-09-05 17:21:01 +04:00
|
|
|
return (ctxt, balance_updates, deactivated)
|
|
|
|
|
|
|
|
let punish ctxt delegate cycle =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
2020-02-12 20:40:17 +04:00
|
|
|
get_frozen_deposit ctxt contract cycle
|
|
|
|
>>=? fun deposit ->
|
|
|
|
get_frozen_fees ctxt contract cycle
|
|
|
|
>>=? fun fees ->
|
|
|
|
get_frozen_rewards ctxt contract cycle
|
|
|
|
>>=? fun rewards ->
|
|
|
|
Roll_storage.Delegate.remove_amount ctxt delegate deposit
|
|
|
|
>>=? fun ctxt ->
|
|
|
|
Roll_storage.Delegate.remove_amount ctxt delegate fees
|
|
|
|
>>=? fun ctxt ->
|
2019-09-05 17:21:01 +04:00
|
|
|
(* Rewards are not accounted in the delegate's rolls yet... *)
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Frozen_deposits.remove (ctxt, contract) cycle
|
|
|
|
>>= fun ctxt ->
|
|
|
|
Storage.Contract.Frozen_fees.remove (ctxt, contract) cycle
|
|
|
|
>>= fun ctxt ->
|
|
|
|
Storage.Contract.Frozen_rewards.remove (ctxt, contract) cycle
|
|
|
|
>>= fun ctxt -> return (ctxt, {deposit; fees; rewards})
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let has_frozen_balance ctxt delegate cycle =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
2020-02-12 20:40:17 +04:00
|
|
|
get_frozen_deposit ctxt contract cycle
|
|
|
|
>>=? fun deposit ->
|
2019-09-05 17:21:01 +04:00
|
|
|
if Tez_repr.(deposit <> zero) then return_true
|
|
|
|
else
|
2020-02-12 20:40:17 +04:00
|
|
|
get_frozen_fees ctxt contract cycle
|
|
|
|
>>=? fun fees ->
|
2019-09-05 17:21:01 +04:00
|
|
|
if Tez_repr.(fees <> zero) then return_true
|
|
|
|
else
|
2020-02-12 20:40:17 +04:00
|
|
|
get_frozen_rewards ctxt contract cycle
|
|
|
|
>>=? fun rewards -> return Tez_repr.(rewards <> zero)
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let frozen_balance_by_cycle_encoding =
|
|
|
|
let open Data_encoding in
|
|
|
|
conv
|
2020-02-12 20:40:17 +04:00
|
|
|
Cycle_repr.Map.bindings
|
2019-09-05 17:21:01 +04:00
|
|
|
(List.fold_left
|
|
|
|
(fun m (c, b) -> Cycle_repr.Map.add c b m)
|
|
|
|
Cycle_repr.Map.empty)
|
2020-02-12 20:40:17 +04:00
|
|
|
(list
|
|
|
|
(merge_objs
|
|
|
|
(obj1 (req "cycle" Cycle_repr.encoding))
|
|
|
|
frozen_balance_encoding))
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let empty_frozen_balance =
|
2020-02-12 20:40:17 +04:00
|
|
|
{deposit = Tez_repr.zero; fees = Tez_repr.zero; rewards = Tez_repr.zero}
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let frozen_balance_by_cycle ctxt delegate =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
|
|
|
let map = Cycle_repr.Map.empty in
|
|
|
|
Storage.Contract.Frozen_deposits.fold
|
2020-02-12 20:40:17 +04:00
|
|
|
(ctxt, contract)
|
|
|
|
~init:map
|
2019-09-05 17:21:01 +04:00
|
|
|
~f:(fun cycle amount map ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Lwt.return
|
|
|
|
(Cycle_repr.Map.add
|
|
|
|
cycle
|
|
|
|
{empty_frozen_balance with deposit = amount}
|
|
|
|
map))
|
|
|
|
>>= fun map ->
|
2019-09-05 17:21:01 +04:00
|
|
|
Storage.Contract.Frozen_fees.fold
|
2020-02-12 20:40:17 +04:00
|
|
|
(ctxt, contract)
|
|
|
|
~init:map
|
2019-09-05 17:21:01 +04:00
|
|
|
~f:(fun cycle amount map ->
|
2020-02-12 20:40:17 +04:00
|
|
|
let balance =
|
|
|
|
match Cycle_repr.Map.find_opt cycle map with
|
|
|
|
| None ->
|
|
|
|
empty_frozen_balance
|
|
|
|
| Some balance ->
|
|
|
|
balance
|
|
|
|
in
|
|
|
|
Lwt.return (Cycle_repr.Map.add cycle {balance with fees = amount} map))
|
|
|
|
>>= fun map ->
|
2019-09-05 17:21:01 +04:00
|
|
|
Storage.Contract.Frozen_rewards.fold
|
2020-02-12 20:40:17 +04:00
|
|
|
(ctxt, contract)
|
|
|
|
~init:map
|
2019-09-05 17:21:01 +04:00
|
|
|
~f:(fun cycle amount map ->
|
2020-02-12 20:40:17 +04:00
|
|
|
let balance =
|
|
|
|
match Cycle_repr.Map.find_opt cycle map with
|
|
|
|
| None ->
|
|
|
|
empty_frozen_balance
|
|
|
|
| Some balance ->
|
|
|
|
balance
|
|
|
|
in
|
|
|
|
Lwt.return (Cycle_repr.Map.add cycle {balance with rewards = amount} map))
|
|
|
|
>>= fun map -> Lwt.return map
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let frozen_balance ctxt delegate =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
|
|
|
let balance = Ok Tez_repr.zero in
|
|
|
|
Storage.Contract.Frozen_deposits.fold
|
2020-02-12 20:40:17 +04:00
|
|
|
(ctxt, contract)
|
|
|
|
~init:balance
|
2019-09-05 17:21:01 +04:00
|
|
|
~f:(fun _cycle amount acc ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Lwt.return acc >>=? fun acc -> Lwt.return Tez_repr.(acc +? amount))
|
|
|
|
>>= fun balance ->
|
2019-09-05 17:21:01 +04:00
|
|
|
Storage.Contract.Frozen_fees.fold
|
2020-02-12 20:40:17 +04:00
|
|
|
(ctxt, contract)
|
|
|
|
~init:balance
|
2019-09-05 17:21:01 +04:00
|
|
|
~f:(fun _cycle amount acc ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Lwt.return acc >>=? fun acc -> Lwt.return Tez_repr.(acc +? amount))
|
|
|
|
>>= fun balance ->
|
2019-09-05 17:21:01 +04:00
|
|
|
Storage.Contract.Frozen_rewards.fold
|
2020-02-12 20:40:17 +04:00
|
|
|
(ctxt, contract)
|
|
|
|
~init:balance
|
2019-09-05 17:21:01 +04:00
|
|
|
~f:(fun _cycle amount acc ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Lwt.return acc >>=? fun acc -> Lwt.return Tez_repr.(acc +? amount))
|
|
|
|
>>= fun balance -> Lwt.return balance
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let full_balance ctxt delegate =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
2020-02-12 20:40:17 +04:00
|
|
|
frozen_balance ctxt delegate
|
|
|
|
>>=? fun frozen_balance ->
|
|
|
|
Storage.Contract.Balance.get ctxt contract
|
|
|
|
>>=? fun balance -> Lwt.return Tez_repr.(frozen_balance +? balance)
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let deactivated = Roll_storage.Delegate.is_inactive
|
|
|
|
|
|
|
|
let grace_period ctxt delegate =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
|
|
|
Storage.Contract.Delegate_desactivation.get ctxt contract
|
|
|
|
|
|
|
|
let staking_balance ctxt delegate =
|
|
|
|
let token_per_rolls = Constants_storage.tokens_per_roll ctxt in
|
2020-02-12 20:40:17 +04:00
|
|
|
Roll_storage.get_rolls ctxt delegate
|
|
|
|
>>=? fun rolls ->
|
|
|
|
Roll_storage.get_change ctxt delegate
|
|
|
|
>>=? fun change ->
|
2019-09-05 17:21:01 +04:00
|
|
|
let rolls = Int64.of_int (List.length rolls) in
|
2020-02-12 20:40:17 +04:00
|
|
|
Lwt.return Tez_repr.(token_per_rolls *? rolls)
|
|
|
|
>>=? fun balance -> Lwt.return Tez_repr.(balance +? change)
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let delegated_balance ctxt delegate =
|
|
|
|
let contract = Contract_repr.implicit_contract delegate in
|
2020-02-12 20:40:17 +04:00
|
|
|
staking_balance ctxt delegate
|
|
|
|
>>=? fun staking_balance ->
|
|
|
|
Storage.Contract.Balance.get ctxt contract
|
|
|
|
>>= fun self_staking_balance ->
|
2019-09-05 17:21:01 +04:00
|
|
|
Storage.Contract.Frozen_deposits.fold
|
2020-02-12 20:40:17 +04:00
|
|
|
(ctxt, contract)
|
|
|
|
~init:self_staking_balance
|
2019-09-05 17:21:01 +04:00
|
|
|
~f:(fun _cycle amount acc ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Lwt.return acc >>=? fun acc -> Lwt.return Tez_repr.(acc +? amount))
|
|
|
|
>>= fun self_staking_balance ->
|
2019-09-05 17:21:01 +04:00
|
|
|
Storage.Contract.Frozen_fees.fold
|
2020-02-12 20:40:17 +04:00
|
|
|
(ctxt, contract)
|
|
|
|
~init:self_staking_balance
|
2019-09-05 17:21:01 +04:00
|
|
|
~f:(fun _cycle amount acc ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Lwt.return acc >>=? fun acc -> Lwt.return Tez_repr.(acc +? amount))
|
|
|
|
>>=? fun self_staking_balance ->
|
2019-09-05 17:21:01 +04:00
|
|
|
Lwt.return Tez_repr.(staking_balance -? self_staking_balance)
|
|
|
|
|
|
|
|
let fold = Storage.Delegates.fold
|
2020-02-12 20:40:17 +04:00
|
|
|
|
2019-09-05 17:21:01 +04:00
|
|
|
let list = Storage.Delegates.elements
|