Skip to content

Commit 7aa3cc1

Browse files
author
Julian Ospald
committed
Allow to return unsigned delegation certificate
1 parent 3222181 commit 7aa3cc1

File tree

11 files changed

+352
-54
lines changed

11 files changed

+352
-54
lines changed

lib/core/src/Cardano/Wallet.hs

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ module Cardano.Wallet
125125
-- ** Delegation
126126
, PoolRetirementEpochInfo (..)
127127
, joinStakePool
128+
, getStakePoolCoinSelection
128129
, quitStakePool
129130
, selectCoinsForDelegation
130131
, estimateFeeForDelegation
@@ -418,6 +419,7 @@ import Statistics.Quantile
418419
import Type.Reflection
419420
( Typeable, typeRep )
420421

422+
import qualified Cardano.Api.Typed as Cardano
421423
import qualified Cardano.Wallet.Primitive.AddressDiscovery.Random as Rnd
422424
import qualified Cardano.Wallet.Primitive.AddressDiscovery.Sequential as Seq
423425
import qualified Cardano.Wallet.Primitive.CoinSelection.Random as CoinSelection
@@ -1714,8 +1716,9 @@ signDelegation
17141716
-> Passphrase "raw"
17151717
-> CoinSelection
17161718
-> DelegationAction
1719+
-> [Cardano.Certificate]
17171720
-> ExceptT ErrSignDelegation IO (Tx, TxMeta, UTCTime, SealedTx)
1718-
signDelegation ctx wid argGenChange pwd coinSel action = db & \DBLayer{..} -> do
1721+
signDelegation ctx wid argGenChange pwd coinSel action certs = db & \DBLayer{..} -> do
17191722
nodeTip <- withExceptT ErrSignDelegationNetwork $ currentNodeTip nl
17201723
withRootKey @_ @s ctx wid pwd ErrSignDelegationWithRootKey $ \xprv scheme -> do
17211724
let pwdP = preparePassphrase scheme pwd
@@ -1733,20 +1736,23 @@ signDelegation ctx wid argGenChange pwd coinSel action = db & \DBLayer{..} -> do
17331736
case action of
17341737
RegisterKeyAndJoin poolId ->
17351738
mkDelegationJoinTx tl poolId
1739+
certs
17361740
(rewardAcnt, pwdP)
17371741
keyFrom
17381742
(nodeTip ^. #slotNo)
17391743
coinSel'
17401744

17411745
Join poolId ->
17421746
mkDelegationJoinTx tl poolId
1747+
certs
17431748
(rewardAcnt, pwdP)
17441749
keyFrom
17451750
(nodeTip ^. #slotNo)
17461751
coinSel'
17471752

17481753
Quit ->
17491754
mkDelegationQuitTx tl
1755+
certs
17501756
(rewardAcnt, pwdP)
17511757
keyFrom
17521758
(nodeTip ^. #slotNo)
@@ -1934,16 +1940,12 @@ getTransaction ctx wid tid = db & \DBLayer{..} -> do
19341940
Delegation
19351941
-------------------------------------------------------------------------------}
19361942

1937-
-- | Helper function to factor necessary logic for joining a stake pool.
1938-
joinStakePool
1943+
-- | Get the coin selection for joining a stake pool.
1944+
getStakePoolCoinSelection
19391945
:: forall ctx s t k.
19401946
( HasDBLayer s k ctx
19411947
, HasLogger WalletLog ctx
1942-
, HasNetworkLayer t ctx
19431948
, HasTransactionLayer t k ctx
1944-
, IsOwned s k
1945-
, IsOurs s ChimericAccount
1946-
, GenChange s
19471949
, HardDerivation k
19481950
, AddressIndexDerivationType k ~ 'Soft
19491951
, WalletKey k
@@ -1954,10 +1956,9 @@ joinStakePool
19541956
-> PoolId
19551957
-> PoolLifeCycleStatus
19561958
-> WalletId
1957-
-> ArgGenChange s
19581959
-> Passphrase "raw"
1959-
-> ExceptT ErrJoinStakePool IO (Tx, TxMeta, UTCTime)
1960-
joinStakePool ctx currentEpoch knownPools pid poolStatus wid argGenChange pwd =
1960+
-> ExceptT ErrJoinStakePool IO (CoinSelection, [Cardano.Certificate], DelegationAction)
1961+
getStakePoolCoinSelection ctx currentEpoch knownPools pid poolStatus wid pwd =
19611962
db & \DBLayer{..} -> do
19621963

19631964
(isKeyReg, walMeta) <- mapExceptT atomically
@@ -1976,21 +1977,62 @@ joinStakePool ctx currentEpoch knownPools pid poolStatus wid argGenChange pwd =
19761977
let action = if isKeyReg then Join pid else RegisterKeyAndJoin pid
19771978
liftIO $ traceWith tr $ MsgIsStakeKeyRegistered isKeyReg
19781979

1979-
selection <- withExceptT ErrJoinStakePoolSelectCoin $
1980+
cs <- withExceptT ErrJoinStakePoolSelectCoin $
19801981
selectCoinsForDelegation @ctx @s @t @k ctx wid action
19811982

1983+
withRootKey @_ @s ctx wid pwd ErrJoinStakePoolRootKey $ \xprv scheme -> do
1984+
let pwdP = preparePassphrase scheme pwd
1985+
let rewardAcnt = getRawKey $ deriveRewardAccount @k pwdP xprv
1986+
let certs = (mkDelegationCertificates tl) (W.Join pid)
1987+
(rewardAcnt, pwdP) cs
1988+
1989+
pure (cs, certs, action)
1990+
1991+
where
1992+
tl = ctx ^. transactionLayer @t @k
1993+
db = ctx ^. dbLayer @s @k
1994+
tr = ctx ^. logger
1995+
1996+
-- | Helper function to factor necessary logic for joining a stake pool.
1997+
joinStakePool
1998+
:: forall ctx s t k.
1999+
( HasDBLayer s k ctx
2000+
, HasLogger WalletLog ctx
2001+
, HasNetworkLayer t ctx
2002+
, HasTransactionLayer t k ctx
2003+
, IsOwned s k
2004+
, IsOurs s ChimericAccount
2005+
, GenChange s
2006+
, HardDerivation k
2007+
, AddressIndexDerivationType k ~ 'Soft
2008+
, WalletKey k
2009+
)
2010+
=> ctx
2011+
-> W.EpochNo
2012+
-> Set PoolId
2013+
-> PoolId
2014+
-> PoolLifeCycleStatus
2015+
-> WalletId
2016+
-> ArgGenChange s
2017+
-> Passphrase "raw"
2018+
-> ExceptT ErrJoinStakePool IO (Tx, TxMeta, UTCTime)
2019+
joinStakePool ctx currentEpoch knownPools pid poolStatus wid argGenChange pwd =
2020+
db & \DBLayer{..} -> do
2021+
(selection, certs, action) <- getStakePoolCoinSelection @ctx @s @t @k
2022+
ctx currentEpoch knownPools pid poolStatus wid pwd
2023+
19822024
(tx, txMeta, txTime, sealedTx) <-
19832025
withExceptT ErrJoinStakePoolSignDelegation $
19842026
signDelegation
19852027
@ctx @s @t @k ctx wid argGenChange pwd selection action
2028+
certs
19862029

19872030
withExceptT ErrJoinStakePoolSubmitTx $
19882031
submitTx @ctx @s @t @k ctx wid (tx, txMeta, sealedTx)
19892032

19902033
pure (tx, txMeta, txTime)
19912034
where
19922035
db = ctx ^. dbLayer @s @k
1993-
tr = ctx ^. logger
19942036

19952037
-- | Helper function to factor necessary logic for quitting a stake pool.
19962038
quitStakePool
@@ -2024,14 +2066,22 @@ quitStakePool ctx wid argGenChange pwd = db & \DBLayer{..} -> do
20242066
selection <- withExceptT ErrQuitStakePoolSelectCoin $
20252067
selectCoinsForDelegation @ctx @s @t @k ctx wid action
20262068

2069+
certs <- withRootKey @_ @s ctx wid pwd ErrQuitStakePoolRootKey $ \xprv scheme -> do
2070+
let pwdP = preparePassphrase scheme pwd
2071+
let rewardAcnt = getRawKey $ deriveRewardAccount @k pwdP xprv
2072+
pure $ (mkDelegationCertificates tl) W.Quit
2073+
(rewardAcnt, pwdP) selection
2074+
20272075
(tx, txMeta, txTime, sealedTx) <- withExceptT ErrQuitStakePoolSignDelegation $
20282076
signDelegation @ctx @s @t @k ctx wid argGenChange pwd selection action
2077+
certs
20292078

20302079
withExceptT ErrQuitStakePoolSubmitTx $
20312080
submitTx @ctx @s @t @k ctx wid (tx, txMeta, sealedTx)
20322081

20332082
pure (tx, txMeta, txTime)
20342083
where
2084+
tl = ctx ^. transactionLayer @t @k
20352085
db = ctx ^. dbLayer @s @k
20362086

20372087

@@ -2309,6 +2359,7 @@ data ErrJoinStakePool
23092359
| ErrJoinStakePoolSignDelegation ErrSignDelegation
23102360
| ErrJoinStakePoolSubmitTx ErrSubmitTx
23112361
| ErrJoinStakePoolCannotJoin ErrCannotJoin
2362+
| ErrJoinStakePoolRootKey ErrWithRootKey
23122363
deriving (Generic, Eq, Show)
23132364

23142365
data ErrQuitStakePool
@@ -2317,6 +2368,7 @@ data ErrQuitStakePool
23172368
| ErrQuitStakePoolSignDelegation ErrSignDelegation
23182369
| ErrQuitStakePoolSubmitTx ErrSubmitTx
23192370
| ErrQuitStakePoolCannotQuit ErrCannotQuit
2371+
| ErrQuitStakePoolRootKey ErrWithRootKey
23202372
deriving (Generic, Eq, Show)
23212373

23222374
-- | Errors that can occur when fetching the reward balance of a wallet

lib/core/src/Cardano/Wallet/Api.hs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ import Cardano.Wallet.Api.Types
115115
, ApiAddressInspectData
116116
, ApiAddressT
117117
, ApiByronWallet
118+
, ApiCoinSelectionCertT
118119
, ApiCoinSelectionT
119120
, ApiFee
120121
, ApiNetworkClock
@@ -123,6 +124,7 @@ import Cardano.Wallet.Api.Types
123124
, ApiPoolId
124125
, ApiPostRandomAddressData
125126
, ApiPutAddressesDataT
127+
, ApiSelectCoinsActionDataT
126128
, ApiSelectCoinsDataT
127129
, ApiT
128130
, ApiTransactionT
@@ -304,6 +306,7 @@ type InspectAddress = "addresses"
304306

305307
type CoinSelections n =
306308
SelectCoins n
309+
:<|> SelectCoinsAction n
307310

308311
-- | https://input-output-hk.github.io/cardano-wallet/api/#operation/selectCoins
309312
type SelectCoins n = "wallets"
@@ -313,6 +316,13 @@ type SelectCoins n = "wallets"
313316
:> ReqBody '[JSON] (ApiSelectCoinsDataT n)
314317
:> Post '[JSON] (ApiCoinSelectionT n)
315318

319+
type SelectCoinsAction n = "wallets"
320+
:> Capture "walletId" (ApiT WalletId)
321+
:> "coin-selections"
322+
:> "random"
323+
:> ReqBody '[JSON] (ApiSelectCoinsActionDataT n)
324+
:> Post '[JSON] (ApiCoinSelectionCertT n)
325+
316326
{-------------------------------------------------------------------------------
317327
Transactions
318328

lib/core/src/Cardano/Wallet/Api/Server.hs

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ module Cardano.Wallet.Api.Server
4949
, getUTxOsStatistics
5050
, getWallet
5151
, joinStakePool
52+
, selectCoinsStakePool
5253
, listAddresses
5354
, listTransactions
5455
, getTransaction
@@ -345,6 +346,8 @@ import Data.Generics.Labels
345346
()
346347
import Data.List
347348
( isInfixOf, isSubsequenceOf, sortOn )
349+
import Data.List.NonEmpty
350+
( NonEmpty )
348351
import Data.Map.Strict
349352
( Map )
350353
import Data.Maybe
@@ -417,11 +420,13 @@ import System.Random
417420
import Type.Reflection
418421
( Typeable )
419422

423+
import qualified Cardano.Api.Typed as Cardano
420424
import qualified Cardano.Wallet as W
421425
import qualified Cardano.Wallet.Api.Types as Api
422426
import qualified Cardano.Wallet.Network as NW
423427
import qualified Cardano.Wallet.Primitive.AddressDerivation.Byron as Byron
424428
import qualified Cardano.Wallet.Primitive.AddressDerivation.Icarus as Icarus
429+
import qualified Cardano.Wallet.Primitive.CoinSelection as C
425430
import qualified Cardano.Wallet.Primitive.Slotting as S
426431
import qualified Cardano.Wallet.Primitive.Types as W
427432
import qualified Cardano.Wallet.Registry as Registry
@@ -1119,6 +1124,50 @@ selectCoins ctx gen (ApiT wid) body =
11191124
let outs = coerceCoin <$> body ^. #payments
11201125
liftHandler $ W.selectCoinsExternal @_ @s @t @k wrk wid gen outs withdrawal Nothing
11211126

1127+
selectCoinsStakePool
1128+
:: forall ctx s t n k e.
1129+
( Buildable (ErrValidateSelection t)
1130+
, s ~ SeqState n k
1131+
, HardDerivation k
1132+
, AddressIndexDerivationType k ~ 'Soft
1133+
, WalletKey k
1134+
, ctx ~ ApiLayer s t k
1135+
, e ~ ErrValidateSelection t
1136+
)
1137+
=> ctx
1138+
-> IO (Set PoolId)
1139+
-- ^ Known pools
1140+
-- We could maybe replace this with a @IO (PoolId -> Bool)@
1141+
-> (PoolId -> IO PoolLifeCycleStatus)
1142+
-> PoolId
1143+
-> WalletId
1144+
-> Passphrase "raw"
1145+
-> Handler (Api.ApiCoinSelectionCert n)
1146+
selectCoinsStakePool ctx knownPools getPoolStatus pid wid pwd = do
1147+
poolStatus <- liftIO (getPoolStatus pid)
1148+
pools <- liftIO knownPools
1149+
curEpoch <- getCurrentEpoch ctx
1150+
1151+
(cs, certs, _) <- withWorkerCtx ctx wid liftE liftE $
1152+
\wrk -> liftHandler $
1153+
W.getStakePoolCoinSelection
1154+
@_ @s @t @k wrk
1155+
curEpoch pools pid poolStatus wid pwd
1156+
utx <- liftHandler $ UnsignedTx
1157+
<$> ensureNonEmpty (C.inputs cs) ErrSelectCoinsExternalUnableToAssignInputs
1158+
<*> ensureNonEmpty (C.outputs cs) ErrSelectCoinsExternalUnableToAssignOutputs
1159+
pure $ mkApiCoinSelectionCert certs utx
1160+
where
1161+
-- TODO: factor out
1162+
ensureNonEmpty
1163+
:: forall a. [a]
1164+
-> (WalletId -> ErrSelectCoinsExternal e)
1165+
-> ExceptT (ErrSelectCoinsExternal e) IO (NonEmpty a)
1166+
ensureNonEmpty mxs err = case NE.nonEmpty mxs of
1167+
Nothing -> throwE $ err wid
1168+
Just xs -> pure xs
1169+
1170+
11221171
{-------------------------------------------------------------------------------
11231172
Addresses
11241173
-------------------------------------------------------------------------------}
@@ -1769,24 +1818,37 @@ rndStateChange ctx (ApiT wid) pwd =
17691818
pure (xprv, preparePassphrase scheme pwd)
17701819

17711820
-- | Makes an 'ApiCoinSelection' from the given 'UnsignedTx'.
1772-
mkApiCoinSelection :: forall n. UnsignedTx -> ApiCoinSelection n
1821+
mkApiCoinSelection :: forall (n :: NetworkDiscriminant). UnsignedTx -> ApiCoinSelection n
17731822
mkApiCoinSelection (UnsignedTx inputs outputs) =
17741823
ApiCoinSelection
17751824
(mkApiCoinSelectionInput <$> inputs)
1776-
(mkAddressAmount <$> outputs)
1777-
where
1778-
mkAddressAmount :: TxOut -> AddressAmount (ApiT Address, Proxy n)
1779-
mkAddressAmount (TxOut addr (Coin c)) =
1780-
AddressAmount (ApiT addr, Proxy @n) (Quantity $ fromIntegral c)
1781-
1782-
mkApiCoinSelectionInput :: (TxIn, TxOut) -> ApiCoinSelectionInput n
1783-
mkApiCoinSelectionInput (TxIn txid index, TxOut addr (Coin c)) =
1784-
ApiCoinSelectionInput
1785-
{ id = ApiT txid
1786-
, index = index
1787-
, address = (ApiT addr, Proxy @n)
1788-
, amount = Quantity $ fromIntegral c
1789-
}
1825+
(mkAddressAmount @n <$> outputs)
1826+
1827+
mkAddressAmount
1828+
:: forall (n :: NetworkDiscriminant). TxOut -> AddressAmount (ApiT Address, Proxy n)
1829+
mkAddressAmount (TxOut addr (Coin c)) =
1830+
AddressAmount (ApiT addr, Proxy @n) (Quantity $ fromIntegral c)
1831+
1832+
mkApiCoinSelectionInput
1833+
:: forall (n :: NetworkDiscriminant). (TxIn, TxOut) -> ApiCoinSelectionInput n
1834+
mkApiCoinSelectionInput (TxIn txid index, TxOut addr (Coin c)) =
1835+
ApiCoinSelectionInput
1836+
{ id = ApiT txid
1837+
, index = index
1838+
, address = (ApiT addr, Proxy @n)
1839+
, amount = Quantity $ fromIntegral c
1840+
}
1841+
1842+
-- | Makes an 'ApiCoinSelection' from the given 'UnsignedTx'.
1843+
mkApiCoinSelectionCert
1844+
:: forall (n :: NetworkDiscriminant). [Cardano.Certificate]
1845+
-> UnsignedTx
1846+
-> Api.ApiCoinSelectionCert n
1847+
mkApiCoinSelectionCert certs (UnsignedTx inputs outputs) =
1848+
Api.ApiCoinSelectionCert
1849+
(mkApiCoinSelectionInput <$> inputs)
1850+
(mkAddressAmount @n <$> outputs)
1851+
(ApiT <$> certs)
17901852

17911853
mkApiTransaction
17921854
:: forall n m. Monad m

0 commit comments

Comments
 (0)