packages feed

morley-client-0.3.0: src/Morley/Client/Action/Delegation.hs

-- SPDX-FileCopyrightText: 2022 Oxhead Alpha
-- SPDX-License-Identifier: LicenseRef-MIT-OA

module Morley.Client.Action.Delegation
  ( setDelegateOp
  , registerDelegateOp
  ) where

import Colog.Core.Class (HasLog)
import Colog.Message (Message)

import Morley.Client.Action.Common
import Morley.Client.Action.Operation
import Morley.Client.RPC.Class
import Morley.Client.RPC.Types
import Morley.Client.TezosClient.Class
import Morley.Client.Types
import Morley.Tezos.Address
import Morley.Tezos.Address.Alias
import Morley.Tezos.Crypto

-- | Set or revoke a delegate for the sender.
--   To set a supply @Just delegate@ as the second argument.
--   To withdraw a delegate supply @Nothing@ as the second argument.
--
--   Some notes on delegations:
--
--   Implicit Accounts can either be /registered delegates/, have no delegate,
--   or have a delegate set without being /registered delegates/ themselves.
--
--   For example imagine two implicit addresses Alice and Bob:
--   * Alice registers as delegate using `registerDelegateOp`. This means that Alice delegates to Alice.
--   * Bob sets Alice as his delegate. This delegates Bob's staking rights to Alice.
--
--   Now, Alice can't change their delegate, because that would revoke Alice as delegate and make
--   Bob's delegation void. So @setDelegateOp alice Nothing@ would throw a @FailedUnDelegation alice@ exception.
--
--   However, Bob, not beeing a /registered delegate/ can:
--   * Revoke the delegation to alice @setDelegateOp bob Nothing@
--   * Delegate to another "registered delegate": @registerDelegateOp charly >> setDelegateOp bob charly@
--   * Become a registered delegate himself: @registerDelegateOp bob@
--
--   Smart Contracts can also delegate to /registered delegates/, but can't be /registered delegates/ themselves.
--
setDelegateOp
  :: ( HasTezosRpc m
     , HasTezosClient m
     , MonadReader env m
     , HasLog env Message m)
  => ImplicitAddressOrAlias
  -> Maybe KeyHash
  -> m OperationHash
setDelegateOp sender delegate =
  fmap fst . runOperationsNonEmpty sender . one . OpDelegation $ DelegationData delegate Nothing

-- | Register the sender as its delegate and become a "registered delegate"
--   Alias for @setDelegateOp sender (Just sender)@
registerDelegateOp
  :: ( HasTezosRpc m
     , HasTezosClient m
     , MonadReader env m
     , HasLog env Message m)
  => KeyHash
  -> m OperationHash
registerDelegateOp sender = setDelegateOp (AddressResolved . ImplicitAddress $ sender) (Just sender)