Skip to content

Commit

Permalink
Add functions for retrieving own (un)registered pub stake keys
Browse files Browse the repository at this point in the history
Add DelegateVoteAbstain example
  • Loading branch information
errfrom committed Jul 25, 2024
1 parent aa7d67a commit a9b5fcd
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 19 deletions.
2 changes: 0 additions & 2 deletions examples/ByUrl.purs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import Ctl.Examples.Cip30 as Cip30
import Ctl.Examples.Datums as Datums
import Ctl.Examples.DropTokens as DropTokens
import Ctl.Examples.ECDSA as ECDSA
import Ctl.Examples.Gov.RegisterDrep (contract) as RegisterDrep
import Ctl.Examples.IncludeDatum (contract) as IncludeDatum
import Ctl.Examples.MintsMultipleTokens as MintsMultipleTokens
import Ctl.Examples.NativeScriptMints as NativeScriptMints
Expand Down Expand Up @@ -241,7 +240,6 @@ examples = addSuccessLog <$> Map.fromFoldable
, "ChangeGeneration1-3" /\
ChangeGeneration.checkChangeOutputsDistribution 1 3 7
, "IncludeDatum" /\ IncludeDatum.contract
, "Gov.RegisterDrep" /\ RegisterDrep.contract
]

addSuccessLog :: Contract Unit -> Contract Unit
Expand Down
58 changes: 58 additions & 0 deletions examples/Gov/DelegateVoteAbstain.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
module Ctl.Examples.Gov.DelegateVoteAbstain
( contract
, example
, main
) where

import Contract.Prelude

import Cardano.Transaction.Builder (TransactionBuilderStep(IssueCertificate))
import Cardano.Types.Certificate (Certificate(VoteRegDelegCert))
import Cardano.Types.Credential (Credential(PubKeyHashCredential))
import Cardano.Types.DRep (DRep(AlwaysAbstain))
import Cardano.Types.PublicKey (hash) as PublicKey
import Cardano.Types.Transaction (hash) as Transaction
import Contract.Config
( ContractParams
, WalletSpec(ConnectToGenericCip30)
, testnetConfig
)
import Contract.Log (logDebug', logInfo')
import Contract.Monad (Contract, launchAff_, runContract)
import Contract.ProtocolParameters (getProtocolParameters)
import Contract.Transaction (awaitTxConfirmed, submitTxFromBuildPlan)
import Contract.Wallet (ownUnregisteredPubStakeKeys)
import Data.Array (head) as Array
import Data.Map (empty) as Map
import Effect.Exception (error)

main :: Effect Unit
main = example $ testnetConfig
{ walletSpec = Just $ ConnectToGenericCip30 "eternl" { cip95: true }
}

example :: ContractParams -> Effect Unit
example = launchAff_ <<< flip runContract contract

contract :: Contract Unit
contract = do
logInfo' "Running Examples.Gov.DelegateVoteAbstain"

unregPubStakeKeys <- ownUnregisteredPubStakeKeys
logDebug' $ "Unregistered public stake keys: " <> show unregPubStakeKeys

pubStakeKey <- liftM (error "Failed to get unregistered pub stake key") $
Array.head unregPubStakeKeys
let stakeCred = wrap $ PubKeyHashCredential $ PublicKey.hash pubStakeKey

stakeCredDeposit <- _.stakeAddressDeposit <<< unwrap <$>
getProtocolParameters

tx <- submitTxFromBuildPlan Map.empty mempty
[ IssueCertificate
(VoteRegDelegCert stakeCred AlwaysAbstain stakeCredDeposit)
Nothing
]

awaitTxConfirmed $ Transaction.hash tx
logInfo' "Tx submitted successfully!"
2 changes: 1 addition & 1 deletion examples/Gov/RegisterDrep.purs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import Contract.Wallet (ownDrepPubKeyHash)

main :: Effect Unit
main = example $ testnetConfig
{ walletSpec = Just $ ConnectToGenericCip30 "nami" { cip95: true }
{ walletSpec = Just $ ConnectToGenericCip30 "eternl" { cip95: true }
}

example :: ContractParams -> Effect Unit
Expand Down
2 changes: 1 addition & 1 deletion packages.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ let additions =
, "prelude"
]
, repo = "https://github.com/mlabs-haskell/purescript-cip95"
, version = "9d92a38cddd318245010286ae3966cd515d6952f"
, version = "ddcabbcf96ec6e292ca821c86eada1f828da0daf"
}
, cip95-typesafe =
{ dependencies =
Expand Down
6 changes: 3 additions & 3 deletions spago-packages.nix

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/Contract/Wallet.purs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ import Ctl.Internal.Contract.Wallet
, ownDrepPubKey
, ownDrepPubKeyHash
, ownPaymentPubKeyHashes
, ownRegisteredPubStakeKeys
, ownStakePubKeyHashes
, ownUnregisteredPubStakeKeys
, signData
) as X
import Ctl.Internal.Contract.Wallet
Expand Down
8 changes: 7 additions & 1 deletion src/Internal/BalanceTx/BalanceTx.purs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import Prelude
import Cardano.Transaction.Edit (editTransaction)
import Cardano.Types
( AssetClass(AssetClass)
, Certificate(StakeDeregistration, StakeRegistration, RegDrepCert)
, Certificate
( StakeDeregistration
, StakeRegistration
, VoteRegDelegCert
, RegDrepCert
)
, Coin(Coin)
, Language(PlutusV1)
, PlutusScript(PlutusScript)
Expand Down Expand Up @@ -834,6 +839,7 @@ getCertsBalance tx (ProtocolParameters pparams) =
( case _ of
StakeRegistration _ -> stakeAddressDeposit
StakeDeregistration _ -> negate $ stakeAddressDeposit
VoteRegDelegCert _ _ deposit -> BigNum.toBigInt $ unwrap deposit
RegDrepCert _ deposit _ -> BigNum.toBigInt $ unwrap deposit
_ -> zero
)
Expand Down
57 changes: 54 additions & 3 deletions src/Internal/Contract/Wallet.purs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ module Ctl.Internal.Contract.Wallet
, ownDrepPubKeyHash
, ownPubKeyHashes
, ownPaymentPubKeyHashes
, ownRegisteredPubStakeKeys
, ownStakePubKeyHashes
, ownUnregisteredPubStakeKeys
, withWallet
, getWalletCollateral
, getWalletBalance
Expand All @@ -31,7 +33,12 @@ import Cardano.Types.TransactionUnspentOutput (TransactionUnspentOutput)
import Cardano.Types.UtxoMap (UtxoMap)
import Cardano.Types.Value (Value, valueToCoin)
import Cardano.Types.Value (geq, lovelaceValueOf, sum) as Value
import Cardano.Wallet.Key (getPrivateDrepKey)
import Cardano.Wallet.Key
( KeyWallet
, PrivateStakeKey(PrivateStakeKey)
, getPrivateDrepKey
, getPrivateStakeKey
)
import Control.Monad.Reader.Trans (asks)
import Control.Parallel (parTraverse)
import Ctl.Internal.BalanceTx.Collateral.Select (minRequiredCollateral)
Expand Down Expand Up @@ -259,7 +266,7 @@ getWalletUtxos = do
(unwrap >>> \({ input, output }) -> input /\ output)

ownDrepPubKey :: Contract PublicKey
ownDrepPubKey = do
ownDrepPubKey =
withWallet do
actionBasedOnWallet _.getPubDrepKey
( \kw -> do
Expand All @@ -270,7 +277,7 @@ ownDrepPubKey = do
)

ownDrepPubKeyHash :: Contract Ed25519KeyHash
ownDrepPubKeyHash = do
ownDrepPubKeyHash =
withWallet do
actionBasedOnWallet (map PublicKey.hash <<< _.getPubDrepKey)
( \kw -> do
Expand All @@ -280,3 +287,47 @@ ownDrepPubKeyHash = do
pure $ PublicKey.hash $ PrivateKey.toPublicKey $
unwrap drepKey
)

ownRegisteredPubStakeKeys :: Contract (Array PublicKey)
ownRegisteredPubStakeKeys =
withWallet do
actionBasedOnWallet _.getRegisteredPubStakeKeys
(map _.reg <<< kwPubStakeKeys)

ownUnregisteredPubStakeKeys :: Contract (Array PublicKey)
ownUnregisteredPubStakeKeys =
withWallet do
actionBasedOnWallet _.getUnregisteredPubStakeKeys
(map _.unreg <<< kwPubStakeKeys)

kwPubStakeKeys
:: KeyWallet
-> Contract { reg :: Array PublicKey, unreg :: Array PublicKey }
kwPubStakeKeys kw =
liftAff (getPrivateStakeKey kw) >>= case _ of
Nothing ->
pure mempty
Just (PrivateStakeKey stakeKey) -> do
queryHandle <- getQueryHandle
network <- asks _.networkId
let
pubStakeKey = PrivateKey.toPublicKey stakeKey
stakePkh = wrap $ PublicKey.hash pubStakeKey
resp <- liftAff $ queryHandle.getPubKeyHashDelegationsAndRewards
network
stakePkh
case resp of
Left err ->
liftEffect $ throw $
"kwPubStakeKeys: getPubKeyHashDelegationsAndRewards call error: "
<> pprintClientError err
Right mStakeAccount ->
pure case mStakeAccount of
Nothing ->
{ reg: mempty
, unreg: Array.singleton pubStakeKey
}
Just _ ->
{ reg: Array.singleton pubStakeKey
, unreg: mempty
}
6 changes: 5 additions & 1 deletion src/Internal/Types/TxConstraints.purs
Original file line number Diff line number Diff line change
Expand Up @@ -670,5 +670,9 @@ mustSatisfyAnyOf =
mustNotBeValid :: Warn TxConstraintsDeprecated => TxConstraints
mustNotBeValid = singleton $ MustNotBeValid

mustRegisterDrep :: Credential -> Maybe Anchor -> TxConstraints
mustRegisterDrep
:: Warn TxConstraintsDeprecated
=> Credential
-> Maybe Anchor
-> TxConstraints
mustRegisterDrep drepCred = singleton <<< MustRegisterDrep drepCred
40 changes: 33 additions & 7 deletions src/Internal/Wallet/Cip30.purs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ import Cardano.Wallet.Cip30 (Api)
import Cardano.Wallet.Cip30.TypeSafe (APIError)
import Cardano.Wallet.Cip30.TypeSafe as Cip30
import Cardano.Wallet.Cip95 (Api) as Cip95
import Cardano.Wallet.Cip95.TypeSafe (getPubDrepKey) as Cip95
import Cardano.Wallet.Cip95.TypeSafe
( getPubDrepKey
, getRegisteredPubStakeKeys
, getUnregisteredPubStakeKeys
) as Cip95
import Control.Monad.Error.Class (catchError, liftMaybe, throwError)
import Ctl.Internal.Helpers (liftM)
import Data.ByteArray (byteArrayToHex, hexToByteArray)
Expand Down Expand Up @@ -85,6 +89,8 @@ type Cip30Wallet =
, signTx :: Transaction -> Aff Transaction
, signData :: Address -> RawBytes -> Aff DataSignature
, getPubDrepKey :: Aff PublicKey
, getRegisteredPubStakeKeys :: Aff (Array PublicKey)
, getUnregisteredPubStakeKeys :: Aff (Array PublicKey)
}

mkCip30WalletAff
Expand All @@ -106,6 +112,8 @@ mkCip30WalletAff conn95 = do
, signTx: signTx connection
, signData: signData connection
, getPubDrepKey: getPubDrepKey conn95
, getRegisteredPubStakeKeys: getRegisteredPubStakeKeys conn95
, getUnregisteredPubStakeKeys: getUnregisteredPubStakeKeys conn95
}

-------------------------------------------------------------------------------
Expand Down Expand Up @@ -247,9 +255,27 @@ getCip30Collateral conn (Coin requiredValue) = do
getPubDrepKey :: Cip95.Api -> Aff PublicKey
getPubDrepKey conn = do
drepKeyHex <- handleApiError =<< Cip95.getPubDrepKey conn
let drepKey = PublicKey.fromRawBytes <<< wrap =<< hexToByteArray drepKeyHex
liftM
( error $ "CIP-95 getPubDRepKey returned invalid DRep key: "
<> drepKeyHex
)
drepKey
pubKeyFromHex drepKeyHex $
"CIP-95 getPubDRepKey returned invalid DRep key: "
<> drepKeyHex

getRegisteredPubStakeKeys :: Cip95.Api -> Aff (Array PublicKey)
getRegisteredPubStakeKeys conn = do
keys <- handleApiError =<< Cip95.getRegisteredPubStakeKeys conn
for keys \pubStakeKeyHex ->
pubKeyFromHex pubStakeKeyHex $
"CIP-95 getRegisteredPubStakeKeys returned invalid key: "
<> pubStakeKeyHex

getUnregisteredPubStakeKeys :: Cip95.Api -> Aff (Array PublicKey)
getUnregisteredPubStakeKeys conn = do
keys <- handleApiError =<< Cip95.getUnregisteredPubStakeKeys conn
for keys \pubStakeKeyHex ->
pubKeyFromHex pubStakeKeyHex $
"CIP-95 getUnregisteredPubStakeKeys returned invalid key: "
<> pubStakeKeyHex

pubKeyFromHex :: String -> String -> Aff PublicKey
pubKeyFromHex keyHex err =
liftM (error err)
(PublicKey.fromRawBytes <<< wrap =<< hexToByteArray keyHex)

0 comments on commit a9b5fcd

Please sign in to comment.