Skip to content

Commit

Permalink
Merge #3162
Browse files Browse the repository at this point in the history
3162: Add an example for using a Plutus script as stake credential r=Jimbo4350 a=kantp



Co-authored-by: Philipp Kant <philipp.kant@iohk.io>
Co-authored-by: Jordan Millar <jordan.millar@iohk.io>
  • Loading branch information
3 people committed Oct 7, 2021
2 parents 3a2db4a + 179ec4f commit f60b392
Show file tree
Hide file tree
Showing 15 changed files with 731 additions and 28 deletions.
2 changes: 1 addition & 1 deletion cardano-cli/src/Cardano/CLI/Shelley/Commands.hs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ renderAddressCmd cmd =
data StakeAddressCmd
= StakeAddressKeyGen VerificationKeyFile SigningKeyFile
| StakeAddressKeyHash (VerificationKeyOrFile StakeKey) (Maybe OutputFile)
| StakeAddressBuild (VerificationKeyOrFile StakeKey) NetworkId (Maybe OutputFile)
| StakeAddressBuild StakeVerifier NetworkId (Maybe OutputFile)
| StakeRegistrationCert StakeVerifier OutputFile
| StakeCredentialDelegationCert
StakeVerifier
Expand Down
2 changes: 1 addition & 1 deletion cardano-cli/src/Cardano/CLI/Shelley/Parsers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ pStakeAddressCmd =
pStakeAddressKeyHash = StakeAddressKeyHash <$> pStakeVerificationKeyOrFile <*> pMaybeOutputFile

pStakeAddressBuild :: Parser StakeAddressCmd
pStakeAddressBuild = StakeAddressBuild <$> pStakeVerificationKeyOrFile
pStakeAddressBuild = StakeAddressBuild <$> pStakeVerifier
<*> pNetworkId
<*> pMaybeOutputFile

Expand Down
11 changes: 8 additions & 3 deletions cardano-cli/src/Cardano/CLI/Shelley/Run/Genesis.hs
Original file line number Diff line number Diff line change
Expand Up @@ -772,8 +772,8 @@ updateTemplate (SystemStart start)
, sgInitialFunds = Map.fromList
[ (toShelleyAddr addr, toShelleyLovelace v)
| (addr, v) <-
distribute nonDelegCoin utxoAddrsNonDeleg ++
distribute delegCoin utxoAddrsDeleg ++
distribute (nonDelegCoin - subtractForTreasury) utxoAddrsNonDeleg ++
distribute (delegCoin - subtractForTreasury) utxoAddrsDeleg ++
mkStuffedUtxo stuffedUtxoAddrs ]
, sgStaking =
ShelleyGenesisStaking
Expand Down Expand Up @@ -807,8 +807,13 @@ updateTemplate (SystemStart start)
}
(shelleyGenesis, alonzoGenesis)
where
maximumLovelaceSupply :: Word64
maximumLovelaceSupply = sgMaxLovelaceSupply template
-- If the initial funds are equal to the maximum funds, rewards cannot be created.
subtractForTreasury :: Integer
subtractForTreasury = nonDelegCoin `quot` 10
nonDelegCoin, delegCoin :: Integer
nonDelegCoin = fromIntegral $ fromMaybe (sgMaxLovelaceSupply template) (unLovelace <$> mAmountNonDeleg)
nonDelegCoin = fromIntegral (fromMaybe maximumLovelaceSupply (unLovelace <$> mAmountNonDeleg))
delegCoin = fromIntegral amountDeleg

distribute :: Integer -> [AddressInEra ShelleyEra] -> [(AddressInEra ShelleyEra, Lovelace)]
Expand Down
43 changes: 30 additions & 13 deletions cardano-cli/src/Cardano/CLI/Shelley/Run/StakeAddress.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ renderShelleyStakeAddressCmdError err =
runStakeAddressCmd :: StakeAddressCmd -> ExceptT ShelleyStakeAddressCmdError IO ()
runStakeAddressCmd (StakeAddressKeyGen vk sk) = runStakeAddressKeyGen vk sk
runStakeAddressCmd (StakeAddressKeyHash vk mOutputFp) = runStakeAddressKeyHash vk mOutputFp
runStakeAddressCmd (StakeAddressBuild vk nw mOutputFp) = runStakeAddressBuild vk nw mOutputFp
runStakeAddressCmd (StakeAddressBuild stakeVerifier nw mOutputFp) =
runStakeAddressBuild stakeVerifier nw mOutputFp
runStakeAddressCmd (StakeRegistrationCert stakeVerifier outputFp) =
runStakeCredentialRegistrationCert stakeVerifier outputFp
runStakeAddressCmd (StakeCredentialDelegationCert stakeVerifier stkPoolVerKeyHashOrFp outputFp) =
Expand Down Expand Up @@ -82,20 +83,36 @@ runStakeAddressKeyHash stakeVerKeyOrFile mOutputFp = do
Just (OutputFile fpath) -> liftIO $ BS.writeFile fpath hexKeyHash
Nothing -> liftIO $ BS.putStrLn hexKeyHash

runStakeAddressBuild :: VerificationKeyOrFile StakeKey -> NetworkId -> Maybe OutputFile
-> ExceptT ShelleyStakeAddressCmdError IO ()
runStakeAddressBuild stakeVerKeyOrFile network mOutputFp = do
stakeVerKey <- firstExceptT ShelleyStakeAddressCmdReadKeyFileError
. newExceptT
$ readVerificationKeyOrFile AsStakeKey stakeVerKeyOrFile
runStakeAddressBuild
:: StakeVerifier
-> NetworkId
-> Maybe OutputFile
-> ExceptT ShelleyStakeAddressCmdError IO ()
runStakeAddressBuild stakeVerifier network mOutputFp =
case stakeVerifier of
StakeVerifierScriptFile (ScriptFile sFile) -> do
ScriptInAnyLang _ script <- firstExceptT ShelleyStakeAddressCmdReadScriptFileError
$ readFileScriptInAnyLang sFile
let stakeCred = StakeCredentialByScript $ hashScript script
stakeAddr = makeStakeAddress network stakeCred
stakeAddrText = serialiseAddress stakeAddr

let stakeCred = StakeCredentialByKey (verificationKeyHash stakeVerKey)
stakeAddr = makeStakeAddress network stakeCred
stakeAddrText = serialiseAddress stakeAddr
case mOutputFp of
Just (OutputFile fpath) -> liftIO $ Text.writeFile fpath stakeAddrText
Nothing -> liftIO $ Text.putStrLn stakeAddrText

StakeVerifierKey stakeVerKeyOrFile -> do
stakeVerKey <- firstExceptT ShelleyStakeAddressCmdReadKeyFileError
. newExceptT
$ readVerificationKeyOrFile AsStakeKey stakeVerKeyOrFile

let stakeCred = StakeCredentialByKey (verificationKeyHash stakeVerKey)
stakeAddr = makeStakeAddress network stakeCred
stakeAddrText = serialiseAddress stakeAddr

case mOutputFp of
Just (OutputFile fpath) -> liftIO $ Text.writeFile fpath stakeAddrText
Nothing -> liftIO $ Text.putStrLn stakeAddrText
case mOutputFp of
Just (OutputFile fpath) -> liftIO $ Text.writeFile fpath stakeAddrText
Nothing -> liftIO $ Text.putStrLn stakeAddrText


runStakeCredentialRegistrationCert
Expand Down
1 change: 0 additions & 1 deletion cardano-cli/src/Cardano/CLI/Shelley/Run/Transaction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,6 @@ runTxBuild (AnyCardanoEra era) (AnyConsensusModeParams cModeParams) networkId mS
metadataSchema scriptFiles metadataFiles mpparams mUpdatePropFile outBody@(TxBodyFile fpath)
mOverrideWits = do
SocketPath sockPath <- firstExceptT ShelleyTxCmdSocketEnvError readEnvSocketPath

let localNodeConnInfo = LocalNodeConnectInfo cModeParams networkId sockPath
consensusMode = consensusModeOnly cModeParams
dummyFee = Just $ Lovelace 0
Expand Down
9 changes: 6 additions & 3 deletions cardano-cli/test/Test/Golden/Shelley/Genesis/Create.hs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ golden_shelleyGenesisCreate = propertyOnce $ do
actualStartTime === fmtStartTime
actualDelegateCount === delegateCount
actualDelegateCount === utxoCount
actualTotalSupply === supply -- Check that the sum of the initial fund amounts matches the total supply
actualTotalSupply === supply - 1000000 -- Check that the sum of the initial fund amounts matches the total supply
-- We don't use the entire supply so there is ada in the treasury. This is
-- required for stake pool rewards.

-- Check uniqueness and count of hash keys
S.size (S.fromList actualHashKeys) === length actualHashKeys -- This isn't strictly necessary because we use aeson which guarantees uniqueness of keys
Expand Down Expand Up @@ -174,8 +176,9 @@ golden_shelleyGenesisCreate = propertyOnce $ do
actualStartTime === fmtStartTime
actualDelegateCount === delegateCount
actualDelegateCount === utxoCount
actualTotalSupply === supply -- Check that the sum of the initial fund amounts matches the total supply

actualTotalSupply === supply - 1000000 -- Check that the sum of the initial fund amounts matches the total supply
-- We don't use the entire supply so there is ada in the treasury. This is
-- required for stake pool rewards.
-- Check uniqueness and count of hash keys
S.size (S.fromList actualHashKeys) === length actualHashKeys -- This isn't strictly necessary because we use aeson which guarantees uniqueness of keys
S.size (S.fromList actualHashKeys) === delegateCount
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,4 +243,4 @@ hprop_plutus = H.integration . H.runFinallies . H.workspace "chairman" $ \tempAb
, "--testnet-magic", show @Int testnetMagic
]

L.filter (not . T.null) (T.splitOn " " (T.lines result !! 2)) !! 2 === "111111111"
L.filter (not . T.null) (T.splitOn " " (T.lines result !! 2)) !! 2 === "100000000"
Original file line number Diff line number Diff line change
Expand Up @@ -254,4 +254,4 @@ hprop_plutus = Test.integration . HE.runFinallies . HE.workspace "chairman" $ \t

HE.note_ $ Text.unpack result

List.filter (not . Text.null) (Text.splitOn " " (Text.lines result !! 2)) !! 2 === "193333333"
List.filter (not . Text.null) (Text.splitOn " " (Text.lines result !! 2)) !! 2 === "160000000"
3 changes: 2 additions & 1 deletion plutus-example/plutus-example/app/plutus-example.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import System.FilePath.Posix ((</>))
import Cardano.PlutusExample.AlwaysFails (alwaysFailsScript)
import Cardano.PlutusExample.AlwaysSucceeds (alwaysSucceedsScript)
import Cardano.PlutusExample.CustomDatumRedeemerGuess
import Cardano.PlutusExample.DatumRedeemerGuess (guessScript)
import Cardano.PlutusExample.DatumRedeemerGuess (guessScript, guessScriptStake)
import Cardano.PlutusExample.MintingScript (apiExamplePlutusMintingScript)
import Cardano.PlutusExample.ScriptContextChecker
import Cardano.PlutusExample.Sum (sumScript)
Expand All @@ -22,6 +22,7 @@ main = do
_ <- writeFileTextEnvelope (dir </> "always-fails.plutus") Nothing alwaysFailsScript
_ <- writeFileTextEnvelope (dir </> "always-succeeds-spending.plutus") Nothing alwaysSucceedsScript
_ <- writeFileTextEnvelope (dir </> "guess-42-datum-42-txin.plutus") Nothing guessScript
_ <- writeFileTextEnvelope (dir </> "guess-42-stake.plutus") Nothing guessScriptStake
_ <- writeFileTextEnvelope (dir </> "custom-guess-42-datum-42.plutus") Nothing customGuessScript
_ <- writeFileTextEnvelope (dir </> "anyone-can-mint.plutus") Nothing apiExamplePlutusMintingScript
_ <- writeFileTextEnvelope (dir </> "sum.plutus") Nothing sumScript
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

module Cardano.PlutusExample.DatumRedeemerGuess
( guessScript
, guessScriptStake
, datumRedeemerGuessScriptShortBs
) where

Expand Down Expand Up @@ -41,3 +42,20 @@ datumRedeemerGuessScriptShortBs = SBS.toShort . LBS.toStrict $ serialise script
guessScript :: PlutusScript PlutusScriptV1
guessScript = PlutusScriptSerialised datumRedeemerGuessScriptShortBs

{-# INLINEABLE mkValidatorStake #-}
mkValidatorStake :: BuiltinData -> BuiltinData -> ()
mkValidatorStake redeemer _txContext
| redeemer == toBuiltinData (42 :: Integer) = ()
| otherwise = traceError "Incorrect datum. Expected 42."

validatorStake :: Plutus.StakeValidator
validatorStake = Plutus.mkStakeValidatorScript $$(PlutusTx.compile [||mkValidatorStake||])

scriptStake :: Plutus.Script
scriptStake = Plutus.unStakeValidatorScript validatorStake

datumRedeemerGuessScriptStakeShortBs :: SBS.ShortByteString
datumRedeemerGuessScriptStakeShortBs = SBS.toShort . LBS.toStrict $ serialise scriptStake

guessScriptStake :: PlutusScript PlutusScriptV1
guessScriptStake = PlutusScriptSerialised datumRedeemerGuessScriptStakeShortBs
20 changes: 17 additions & 3 deletions scripts/byron-to-alonzo/mkfiles.sh
Original file line number Diff line number Diff line change
Expand Up @@ -310,13 +310,15 @@ cardano-cli genesis create --testnet-magic 42 --genesis-dir shelley
# and K=10, but we'll keep long KES periods so we don't have to bother
# cycling KES keys
sed -i shelley/genesis.spec.json \
-e 's/"slotLength": 1/"slotLength": 0.2/' \
-e 's/"slotLength": 1/"slotLength": 0.1/' \
-e 's/"activeSlotsCoeff": 5.0e-2/"activeSlotsCoeff": 0.1/' \
-e 's/"securityParam": 2160/"securityParam": 10/' \
-e 's/"epochLength": 432000/"epochLength": 1500/' \
-e 's/"epochLength": 432000/"epochLength": 500/' \
-e 's/"maxLovelaceSupply": 0/"maxLovelaceSupply": 1000000000000/' \
-e 's/"decentralisationParam": 1.0/"decentralisationParam": 0.7/' \
-e 's/"major": 0/"major": 2/' \
-e 's/"major": 0/"major": 5/' \
-e 's/"rho": 0.0/"rho": 0.1/' \
-e 's/"tau": 0.0/"tau": 0.1/' \
-e 's/"updateQuorum": 5/"updateQuorum": 2/'

# Now generate for real:
Expand All @@ -327,6 +329,18 @@ cardano-cli genesis create \
--gen-genesis-keys ${NUM_BFT_NODES} \
--gen-utxo-keys 1

cardano-cli stake-address key-gen \
--verification-key-file shelley/utxo-keys/utxo-stake.vkey \
--signing-key-file shelley/utxo-keys/utxo-stake.skey

cardano-cli address key-gen \
--verification-key-file shelley/utxo-keys/utxo2.vkey \
--signing-key-file shelley/utxo-keys/utxo2.skey

cardano-cli stake-address key-gen \
--verification-key-file shelley/utxo-keys/utxo2-stake.vkey \
--signing-key-file shelley/utxo-keys/utxo2-stake.skey

echo "====================================================================="
echo "Generated genesis keys and genesis files:"
echo
Expand Down
5 changes: 5 additions & 0 deletions scripts/plutus/scripts/guess-42-stake.plutus
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "PlutusScriptV1",
"description": "",
"cborHex": "587a58780100003233322232323233223232225335300a333500900800233500700d4815040184d400d2411d496e636f727265637420646174756d2e2045787065637465642034322e001235002353003335738002008930930900090008900091199ab9a3375e00400200c00a24002244004244002400246ea00041"
}
91 changes: 91 additions & 0 deletions scripts/plutus/staking-example/claim-script-staking-rewards.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env bash

set -e
# Unoffiical bash strict mode.
# See: http://redsymbol.net/articles/unofficial-bash-strict-mode/
set -u
set -o pipefail


export BASE="${BASE:-.}"
export WORK="${WORK:-example/work}"
export CARDANO_NODE_SOCKET_PATH="${CARDANO_NODE_SOCKET_PATH:-example/node-bft1/node.sock}"
export TESTNET_MAGIC="${TESTNET_MAGIC:-42}"
export UTXO_VKEY1="${UTXO_VKEY1:-example/shelley/utxo-keys/utxo1.vkey}"
export UTXO_SKEY1="${UTXO_SKEY1:-example/shelley/utxo-keys/utxo1.skey}"
export UTXO_VKEY2="${UTXO_VKEY1:-example/shelley/utxo-keys/utxo2.vkey}"
export UTXO_SKEY2="${UTXO_SKEY1:-example/shelley/utxo-keys/utxo2.skey}"
export UTXO_STAKING_VKEY1="${UTXO_STAKING_VKEY1:=example/shelley/utxo-keys/utxo-stake.vkey}"
export UTXO_STAKING_SKEY1="${UTXO_STAKING_SKEY1:=example/shelley/utxo-keys/utxo-stake.skey}"
export UTXO_STAKING_VKEY2="${UTXO_STAKING_VKEY2:=example/shelley/utxo-keys/utxo2-stake.vkey}"
export UTXO_STAKING_SKEY2="${UTXO_STAKING_SKEY2:=example/shelley/utxo-keys/utxo2-stake.skey}"

utxoaddr=$(cardano-cli address build --testnet-magic "$TESTNET_MAGIC" --payment-verification-key-file "$UTXO_VKEY1")


cardano-cli query utxo \
--address "$utxoaddr" \
--cardano-mode \
--testnet-magic "$TESTNET_MAGIC" \
--out-file "$WORK/utxo-1.json"

echo "UTxO"
cat "$WORK/utxo-1.json"
echo ""

txin=$(jq -r 'keys[0]' $WORK/utxo-1.json)
txinlovelace=$(jq -r ".[\"$txin\"].value.lovelace" $WORK/utxo-1.json)
txincollateral=$(jq -r 'keys[1]' $WORK/utxo-1.json)
scriptpaymentaddrwithstakecred=$(cardano-cli address build --payment-verification-key-file $UTXO_VKEY1 --stake-script-file "scripts/plutus/scripts/guess-42-stake.plutus" --testnet-magic 42)
stakingscriptaddr=$(cardano-cli stake-address build --stake-script-file scripts/plutus/scripts/guess-42-stake.plutus --testnet-magic 42)

# STEP 1 - Get reward account balance

cardano-cli query stake-address-info \
--address "$stakingscriptaddr" \
--testnet-magic 42 \
--out-file "$WORK/scriptdelegationstatusrewards.json"

rewardamt=$(jq -r '.[0].rewardAccountBalance' $WORK/scriptdelegationstatusrewards.json)

totalspendable=$(expr $rewardamt + $txinlovelace - 289563)
echo "Lovelace at utxo: $txinlovelace"
echo "Rewards: $rewardamt"
echo "Combined: $totalspendable"

cardano-cli transaction build \
--alonzo-era \
--testnet-magic "$TESTNET_MAGIC" \
--change-address "$utxoaddr" \
--tx-in "$txin" \
--tx-in-collateral "$txincollateral" \
--tx-out "$scriptpaymentaddrwithstakecred+$totalspendable" \
--withdrawal "$stakingscriptaddr+$rewardamt" \
--withdrawal-script-file "scripts/plutus/scripts/guess-42-stake.plutus" \
--withdrawal-redeemer-file "scripts/plutus/data/42.redeemer" \
--protocol-params-file "$WORK/pparams.json" \
--out-file "$WORK/script-withdrawal.txbody"

cardano-cli transaction sign \
--tx-body-file "$WORK/script-withdrawal.txbody" \
--testnet-magic "$TESTNET_MAGIC" \
--signing-key-file "$UTXO_SKEY1" \
--out-file "$WORK/script-withdrawal.tx"

echo "Submitting withdrawal..."

cardano-cli transaction submit \
--tx-file "$WORK/script-withdrawal.tx" \
--testnet-magic "$TESTNET_MAGIC"

echo "Waiting 5 seconds...."
sleep 5

cardano-cli query stake-address-info \
--address "$stakingscriptaddr" \
--testnet-magic 42 \
--out-file "$WORK/scriptrewardscheck.json"

scriptrewardscheck=$(jq -r '.[0]' $WORK/scriptrewardscheck.json)
echo "Checking if script rewards withdrawal was successful..."
echo "$scriptrewardscheck"
Loading

0 comments on commit f60b392

Please sign in to comment.