Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an example for using a Plutus script as stake credential #3162

Merged
merged 4 commits into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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