diff --git a/docs/protocols/alpha.rst b/docs/protocols/alpha.rst index 25d39409025e0cf10d77d48e311b9d38ff51f98a..088e33db1fa64d9dd7a8d3147a6443c1df501ecc 100644 --- a/docs/protocols/alpha.rst +++ b/docs/protocols/alpha.rst @@ -38,6 +38,8 @@ Bug Fixes - Fix a discrepancy in gas consumption of contract origination between dry run and actual application (MR :gl:`!5659`) +- Fixes the ``delegated_balance`` rpc, which reported an incorrect value for delegates that have frozen bonds (MR :gl:`!5765`) + Minor Changes ------------- diff --git a/src/proto_alpha/lib_protocol/delegate_services.ml b/src/proto_alpha/lib_protocol/delegate_services.ml index 6a07486f0c1ade58ac04baeffe062e7ce4535f15..61c6656f3fefdd7ca8309a5c06d47c362e5f04f2 100644 --- a/src/proto_alpha/lib_protocol/delegate_services.ml +++ b/src/proto_alpha/lib_protocol/delegate_services.ml @@ -267,7 +267,7 @@ module S = struct ~description: "Returns the sum (in mutez) of all balances of all the contracts that \ delegate to a given delegate. This excludes the delegate's own \ - balance and its frozen deposits." + balance, its frozen deposits and its frozen bonds." ~query:RPC_query.empty ~output:Tez.encoding RPC_path.(path / "delegated_balance") diff --git a/src/proto_alpha/lib_protocol/delegate_storage.ml b/src/proto_alpha/lib_protocol/delegate_storage.ml index d2f0fa7c765693732737e996abd195f996c6f61c..cd9095e5fe58ba4f43bfb2da8e2e336b868ad6ac 100644 --- a/src/proto_alpha/lib_protocol/delegate_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_storage.ml @@ -701,10 +701,7 @@ let deactivated = Delegate_activation_storage.is_inactive let delegated_balance ctxt delegate = staking_balance ctxt delegate >>=? fun staking_balance -> - balance ctxt delegate >>=? fun balance -> - frozen_deposits ctxt delegate >>=? fun frozen_deposits -> - Tez_repr.(balance +? frozen_deposits.current_amount) - >>?= fun self_staking_balance -> + full_balance ctxt delegate >>=? fun self_staking_balance -> Lwt.return Tez_repr.(staking_balance -? self_staking_balance) let fold = Storage.Delegates.fold diff --git a/src/proto_alpha/lib_protocol/test/integration/test_frozen_bonds.ml b/src/proto_alpha/lib_protocol/test/integration/test_frozen_bonds.ml index 27f5394c700a2b0276a33e8f3782f8558e6e49d8..3717b5e8317a35d12345e255f27a2ce4e003b520 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_frozen_bonds.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_frozen_bonds.ml @@ -145,7 +145,7 @@ let test_delegate_then_freeze_deposit () = >>=? fun () -> (* Fetch user's balance again. *) Token.balance ctxt user_account >>>=? fun (_, user_balance') -> - (* Ensure user's balance decreased. *) + (* Ensure user's balance is unchanged. *) Assert.equal_tez ~loc:__LOC__ user_balance' user_balance (** Tested scenario: @@ -202,7 +202,7 @@ let test_freeze_deposit_then_delegate () = >>=? fun () -> (* Fetch user's balance. *) Token.balance ctxt user_account >>>=? fun (_, user_balance') -> - (* Ensure user's balance decreased. *) + (* Ensure user's balance is unchanged. *) Assert.equal_tez ~loc:__LOC__ user_balance' user_balance (** Tested scenario: @@ -303,6 +303,84 @@ let test_total_stake ~user_is_delegate () = Contract.get_balance_and_frozen_bonds ctxt user_contract >>>=? fun stake -> Assert.equal_tez ~loc:__LOC__ stake balance +let check_delegated_balance_is ctxt ~loc delegate expected_balance = + (* Fetch the delegated balance of d. *) + Delegate.delegated_balance ctxt delegate >>>=? fun delegated_balance -> + (* Check that the delegated balance of [delegate] is as explected. *) + Assert.equal_tez ~loc delegated_balance expected_balance + +(** Tested scenario: + 1. freeze some bonds for the delegate, + 2. check that the delegated balance is null, + 3. let user contract delegate to 'delegate', + 4. check that the staking balance of 'delegate' has increased as expected, + 5. check that the delegated balance of 'delegate' is equal to the balance of the delegator, + 6. unfreeze the bonds, + 7. check that the staking balance has not changed, + 8. check that the delegated balance of 'delegate' is equal to the balance of the delegator, + 9. remove the delegation, + 10. check that staking balance has decreased as expected, + 11. check that the delegated balance is null, + 12. check that the user's balance is unchanged. *) +let test_delegated_balance () = + init_test ~user_is_delegate:false + >>=? fun (ctxt, user_contract, user_account, delegate) -> + let delegate_contract = Contract.Implicit delegate in + let delegate_account = `Contract delegate_contract in + (* Fetch user's initial balance before freeze. *) + Token.balance ctxt user_account >>>=? fun (ctxt, user_balance) -> + (* Fetch staking balance before freeze. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance -> + (* Freeze a tx-rollup deposit for the delegate. *) + let tx_rollup, _ = mk_tx_rollup () in + let bond_id = Bond_id.Tx_rollup_bond_id tx_rollup in + let deposit_amount = small_random_amount () in + let deposit_account = `Frozen_bonds (delegate_contract, bond_id) in + Token.transfer ctxt delegate_account deposit_account deposit_amount + >>>=? fun (ctxt, _) -> + (* Check that the delegated balance of [delegate] is null. *) + check_delegated_balance_is ctxt ~loc:__LOC__ delegate Tez.zero >>=? fun () -> + (* Let user delegate to "delegate". *) + Delegate.set ctxt user_contract (Some delegate) >>>=? fun ctxt -> + (* Fetch staking balance after delegation. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance' -> + (* ensure staking balance increased by the user's balance. *) + Assert.equal_tez + ~loc:__LOC__ + staking_balance' + (user_balance +! staking_balance) + >>=? fun () -> + (* Check that the delegated balance of [delegate] is equal to [user_balance]. *) + check_delegated_balance_is ctxt ~loc:__LOC__ delegate user_balance + >>=? fun () -> + (* Unfreeze the deposit. *) + Token.transfer ctxt deposit_account delegate_account deposit_amount + >>>=? fun (ctxt, _) -> + (* Fetch staking balance after unfreeze. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance'' -> + (* Ensure that staking balance is unchanged. *) + Assert.equal_tez ~loc:__LOC__ staking_balance'' staking_balance' + >>=? fun () -> + (* Check that the delegated balance of [delegate] is equal to [user_balance]. *) + check_delegated_balance_is ctxt ~loc:__LOC__ delegate user_balance + >>=? fun () -> + (* Remove delegation. *) + Delegate.set ctxt user_contract None >>>=? fun ctxt -> + (* Fetch staking balance. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance''' -> + (* Check that staking balance has decreased by the user's initial balance. *) + Assert.equal_tez + ~loc:__LOC__ + staking_balance''' + (staking_balance'' -! user_balance) + >>=? fun () -> + (* Check that the delegated balance of [delegate] is null. *) + check_delegated_balance_is ctxt ~loc:__LOC__ delegate Tez.zero >>=? fun () -> + (* Fetch user's balance. *) + Token.balance ctxt user_account >>>=? fun (_, user_balance') -> + (* Ensure user's balance is unchanged. *) + Assert.equal_tez ~loc:__LOC__ user_balance' user_balance + (** Tests that the rpcs [contract/pkh/frozen_bonds] and [contract/pkh/balance_and_frozen_bonds] can be called successfully. These rpcs call the functions [Contract.get_frozen_bonds] and @@ -589,6 +667,7 @@ let tests = "frozen bonds - total stake, user is a delegate" `Quick (test_total_stake ~user_is_delegate:true); + tztest "frozen bonds - delegated balance" `Quick test_delegated_balance; tztest "frozen bonds - test rpcs" `Quick test_rpcs; tztest "test: delegate, freeze, unfreeze, undelegate"