11{-# LANGUAGE ExistentialQuantification #-}
2+ {-# LANGUAGE FlexibleContexts #-}
23{-# LANGUAGE GADTs #-}
34{-# LANGUAGE NamedFieldPuns #-}
45{-# LANGUAGE RankNTypes #-}
78
89module Cardano.Wasm.Api.Certificate.StakeCertificate
910 ( StakeCertificateObject (.. )
10- , createStakeKeyCertificate
11- , asStakeRegistration
12- , asStakeUnregistration
13- , asDelegateOnly
14- , withDeposit
15- , withoutDeposit
16- , withDelegation
17- , withoutDelegation
11+ , createStakeKeyCertificateImpl
12+ , asStakeRegistrationImpl
13+ , asStakeUnregistrationImpl
14+ , asDelegateOnlyImpl
15+ , withDepositImpl
16+ , withoutDepositImpl
17+ , withDelegationImpl
18+ , withoutDelegationImpl
19+ , toCborImpl
1820 )
1921where
2022
21- import Cardano.Api (Coin , Hash , PoolId , StakeKey , ToJSON (.. ))
23+ import Cardano.Api
24+ ( Coin
25+ , Hash
26+ , PoolId
27+ , StakeKey
28+ , ToJSON (.. )
29+ , convert
30+ , conwayEraOnwardsConstraints
31+ , serialiseToCBOR
32+ , unStakeKeyHash
33+ , unStakePoolKeyHash
34+ )
2235import Cardano.Api.Experimental (Era (.. ), obtainCommonConstraints )
2336import Cardano.Api.Experimental qualified as Exp
37+ import Cardano.Api.Experimental.Certificate (Certificate (.. ))
38+ import Cardano.Api.Ledger
39+ ( ConwayDelegCert (.. )
40+ , ConwayTxCert (.. )
41+ , Credential (.. )
42+ , maybeToStrictMaybe
43+ )
2444import Cardano.Api.Serialise.Raw qualified as Api
2545
46+ import Cardano.Ledger.Api (Delegatee (.. ))
2647import Cardano.Wasm.ExceptionHandling (rightOrError , throwError , toMonadFail )
2748
49+ import Control.Monad.Catch (MonadThrow )
2850import Data.Aeson (FromJSON , (.:) , (.=) )
2951import Data.Aeson qualified as Aeson
52+ import Data.ByteString.Base16 qualified as Base16
3053import Data.Text (Text )
54+ import Data.Text qualified as Text
3155import Data.Text.Encoding qualified as Text
3256
3357data StakeCertificateAction
@@ -36,25 +60,20 @@ data StakeCertificateAction
3660 | DelegateOnly
3761 deriving (Show , Eq )
3862
39- data Delegation
40- = NoDelegation
41- | DelegateToPool PoolId
42- -- ToDo: Add DRep delegation
43- deriving (Show , Eq )
44-
4563data StakeCertificateObject
4664 = forall era . StakeCertificateObject
47- { era :: ! (Era era )
65+ { era :: ! (Exp. Era era )
4866 , stakeCredential :: ! (Hash StakeKey ) -- ToDo: Generalize to support scripts as well
4967 , deposit :: ! (Maybe Coin )
5068 , action :: ! StakeCertificateAction
51- , delegation :: Delegation
69+ , delegateStake :: Maybe PoolId
70+ -- ToDo: Add DRep delegation
5271 }
5372
5473deriving instance Show StakeCertificateObject
5574
5675instance ToJSON StakeCertificateObject where
57- toJSON (StakeCertificateObject {era, stakeCredential, deposit, action, delegation }) =
76+ toJSON (StakeCertificateObject {era, stakeCredential, deposit, action, delegateStake }) =
5877 obtainCommonConstraints era $
5978 Aeson. object
6079 [ " era" .= Exp. Some era
@@ -64,9 +83,7 @@ instance ToJSON StakeCertificateObject where
6483 RegisterStake -> Aeson. String " RegisterStake"
6584 UnregisterStake -> Aeson. String " UnregisterStake"
6685 DelegateOnly -> Aeson. String " DelegateOnly"
67- , " delegation" .= case delegation of
68- NoDelegation -> Aeson. String " NoDelegation"
69- DelegateToPool pid -> Aeson. object [" DelegateToPool" .= show pid]
86+ , " delegateStake" .= fmap (Text. decodeUtf8 . Api. serialiseToRawBytesHex) delegateStake
7087 ]
7188
7289instance FromJSON StakeCertificateObject where
@@ -85,73 +102,128 @@ instance FromJSON StakeCertificateObject where
85102 " UnregisterStake" -> return UnregisterStake
86103 " DelegateOnly" -> return DelegateOnly
87104 _ -> toMonadFail $ throwError (" Invalid action for StakeCertificateObject: " ++ show actionStr)
88- delegationVal <- o .: " delegation"
89- delegation <-
90- case delegationVal of
91- Aeson. String " NoDelegation" -> return NoDelegation
92- Aeson. Object obj -> do
93- pidStr :: Text <- obj .: " DelegateToPool"
94- DelegateToPool
95- <$> toMonadFail (rightOrError $ Api. deserialiseFromRawBytesHex $ Text. encodeUtf8 pidStr)
96- _ ->
97- toMonadFail $ throwError (" Invalid delegation for StakeCertificateObject: " ++ show delegationVal)
105+ delegateStakeText :: Maybe Text <- o .: " delegateStake"
106+ delegateStake :: Maybe PoolId <-
107+ traverse
108+ ( toMonadFail
109+ . rightOrError
110+ . Api. deserialiseFromRawBytesHex
111+ . Text. encodeUtf8
112+ )
113+ delegateStakeText
98114 obtainCommonConstraints era $
99115 return $
100116 StakeCertificateObject
101117 { era
102118 , stakeCredential
103119 , deposit
104120 , action
105- , delegation
121+ , delegateStake
106122 }
107123
108124-- | Creates an empty stake certificate object for the given stake key hash.
109125-- For the certificate to be valid must be either a registration, an unregistration or
110126-- a delegation certificate. But it can be both registration and delegation.
111- createStakeKeyCertificate :: Hash StakeKey -> StakeCertificateObject
112- createStakeKeyCertificate skHash =
127+ createStakeKeyCertificateImpl :: Hash StakeKey -> StakeCertificateObject
128+ createStakeKeyCertificateImpl skHash =
113129 StakeCertificateObject
114130 { era = ConwayEra
115131 , stakeCredential = skHash
116132 , deposit = Nothing
117133 , action = DelegateOnly
118- , delegation = NoDelegation
134+ , delegateStake = Nothing
119135 }
120136
121137-- | Marks the certificate as a stake registration certificate.
122- asStakeRegistration :: StakeCertificateObject -> StakeCertificateObject
123- asStakeRegistration certObj =
138+ asStakeRegistrationImpl :: StakeCertificateObject -> StakeCertificateObject
139+ asStakeRegistrationImpl certObj =
124140 certObj{action = RegisterStake }
125141
126142-- | Marks the certificate as a stake un-registration certificate.
127- asStakeUnregistration :: StakeCertificateObject -> StakeCertificateObject
128- asStakeUnregistration certObj =
143+ asStakeUnregistrationImpl :: StakeCertificateObject -> StakeCertificateObject
144+ asStakeUnregistrationImpl certObj =
129145 certObj{action = UnregisterStake }
130146
131147-- | Marks the certificate as a delegation-only certificate (not registration nor un-registration).
132- asDelegateOnly :: StakeCertificateObject -> StakeCertificateObject
133- asDelegateOnly certObj =
148+ asDelegateOnlyImpl :: StakeCertificateObject -> StakeCertificateObject
149+ asDelegateOnlyImpl certObj =
134150 certObj{action = DelegateOnly }
135151
136152-- | Sets the deposit for the stake certificate. This only has effect for stake registration
137153-- and unregistration certificates. The amount must match the expected deposit amount specified by
138154-- 'ppKeyDepositL' in the protocol parameters for registration certificates and the amount
139155-- depositted for unregistration certificates.
140- withDeposit :: Coin -> StakeCertificateObject -> StakeCertificateObject
141- withDeposit dep certObj =
156+ withDepositImpl :: Coin -> StakeCertificateObject -> StakeCertificateObject
157+ withDepositImpl dep certObj =
142158 certObj{deposit = Just dep}
143159
144160-- | Resets the deposit for the stake certificate.
145- withoutDeposit :: StakeCertificateObject -> StakeCertificateObject
146- withoutDeposit certObj =
161+ withoutDepositImpl :: StakeCertificateObject -> StakeCertificateObject
162+ withoutDepositImpl certObj =
147163 certObj{deposit = Nothing }
148164
149165-- | Sets the pool to which the stake key will be delegated.
150- withDelegation :: PoolId -> StakeCertificateObject -> StakeCertificateObject
151- withDelegation poolId certObj =
152- certObj{delegation = DelegateToPool poolId}
166+ withDelegationImpl :: PoolId -> StakeCertificateObject -> StakeCertificateObject
167+ withDelegationImpl poolId certObj =
168+ certObj{delegateStake = Just poolId}
153169
154170-- | Resets the delegation for the stake certificate.
155- withoutDelegation :: StakeCertificateObject -> StakeCertificateObject
156- withoutDelegation certObj =
157- certObj{delegation = NoDelegation }
171+ withoutDelegationImpl :: StakeCertificateObject -> StakeCertificateObject
172+ withoutDelegationImpl certObj =
173+ certObj{delegateStake = Nothing }
174+
175+ -- | Convert a StakeCertificateObject to the base16 encoding of its CBOR representation.
176+ toCborImpl :: MonadThrow m => StakeCertificateObject -> m String
177+ toCborImpl
178+ ( StakeCertificateObject
179+ { era
180+ , stakeCredential
181+ , deposit
182+ , action
183+ , delegateStake
184+ }
185+ ) = do
186+ stakeCert <- toCardanoApiCertificate era stakeCredential deposit action delegateStake
187+ return $
188+ obtainCommonConstraints era $
189+ Text. unpack $
190+ Text. decodeUtf8 $
191+ Base16. encode $
192+ serialiseToCBOR
193+ stakeCert
194+
195+ toCardanoApiCertificate
196+ :: MonadThrow m
197+ => Exp. Era era
198+ -> Hash StakeKey
199+ -> Maybe Coin
200+ -> StakeCertificateAction
201+ -> Maybe PoolId
202+ -> m (Certificate (Exp. LedgerEra era ))
203+ toCardanoApiCertificate era stakeCredential deposit action delegateStake =
204+ Exp. obtainCommonConstraints era $
205+ conwayEraOnwardsConstraints (convert era) $
206+ Certificate . ConwayTxCertDeleg
207+ <$> ( case (action, delegateStake) of
208+ (DelegateOnly , Nothing ) ->
209+ throwError
210+ " Certificate must at least either: register, unregister, or delegate"
211+ (RegisterStake , Nothing ) ->
212+ return $ ConwayRegCert (KeyHashObj $ unStakeKeyHash stakeCredential) (maybeToStrictMaybe deposit)
213+ (UnregisterStake , Nothing ) ->
214+ return $ ConwayUnRegCert (KeyHashObj $ unStakeKeyHash stakeCredential) (maybeToStrictMaybe deposit)
215+ (DelegateOnly , Just poolId) ->
216+ return $
217+ ConwayDelegCert
218+ (KeyHashObj $ unStakeKeyHash stakeCredential)
219+ (DelegStake $ unStakePoolKeyHash poolId)
220+ (RegisterStake , Just poolId) ->
221+ ConwayRegDelegCert
222+ (KeyHashObj $ unStakeKeyHash stakeCredential)
223+ (DelegStake $ unStakePoolKeyHash poolId)
224+ <$> case deposit of
225+ Just dep -> return dep
226+ Nothing -> throwError " Deposit must be specified for stake registration and delegation certificate"
227+ (UnregisterStake , Just _) ->
228+ throwError " Cannot unregister and delegate in the same certificate"
229+ )
0 commit comments