Overview
In this section, we will look at validator scripts as they relate to staking on Cardano. The scripts we looked at so far were only related to the payment part of addresses, i.e. used for the Spending
part of ScriptPurpose
. We will now look at StakeValidator
s which correspond to Certifying
and Rewarding
script purposes.
The Rewarding
script purpose is related to validating reward withdrawals, i.e. whether a transaction is allowed to withdraw rewards from the script stake address.
The Certifying
script purpose is related to validating certificates present in the transaction which control the registration and delegation of the script stake address, i.e. validating whether the transaction can register/de-register the given script stake address and whether it can delegate its funds to the specified stake pool.
Cardano address structure
A Cardano base address (Shelley-based) is composed of two parts, the payment part (which controls spending associated UTxOs) and the optional staking part (which controls delegation-related actions). These two parts have separate keys (payment and stake keys), that are used to sign transactions to prove that they are valid. For example, if we want to register and delegate a stake address to a pool, we must submit a transaction that is signed by the address's stake key to validate it.
Now, with Plutus, the Shelley-based model of addresses remains the same, but we are no longer limited to controlling address validation with just the usual key pairs. Instead, we can create addresses that are composed of two scripts, the payment script (which are scripts that we have been writing so far), and the stake script (which is what we will be writing shortly). This way, we can have arbitrary logic of scripts take over both the payment and the stake part of addresses. We can also make all other possible permutations to build addresses. For example, we can use a payment script and a staking key to create an address that uses script logic to spend its UTxO, but the staking actions of the address are controlled by a staking key. Or we could make an address that uses a payment key and a stake validator. Beautiful.
To confirm this, check the cardano-cli address build --help
command:
It gives the option to provide either the keys or a script file for both payment and stake parts (--payment-script-file
/ --stake-script-file
).
The StakeValidator type
StakeValidator
has a slightly different type signature than the regular validators because it does not accept datum
as the first argument. That makes sense since the datum sits at the UTxO, and we are not dealing with spending UTxO here, only with validating staking actions. Therefore, it only receives the redeemer
and context
to return a boolean value:
type UntypedStakeValidator = BuiltinData -> BuiltinData -> ()
So when writing our mkStakingValidator
function, we would use that type signature. Principles of typed and parameterised validators still apply here so we can write a function in this way: mkStakingValidator :: MyParam -> MyRedeemer -> ScriptContext -> Bool
Going back to the Certifying
and Rewarding
script purposes, we can see that they are constructed as Rewarding StakingCredential
and Certifying DCert
:
If we dive into the Rewarding StakingCredential
, we will find the StakingHash
constructor with the generic Credential
type (the other is a pointer address, which we will not go into here, but here is a reference for those interested: https://docs.cardano.org/learn/cardano-addresses):
The Credential
type is either a PubKeyHash
or a ValidatorHash
depending on whether it's a normal or script address:
For Certifying DCert
, we dive into DCert
definition:
This is the full definition of DCert
and it contains fields not really related to delegation per se (DCertGenesis
and DCertMir
). We can also see certificates related to pool registration/de-registration which we are not interested in from the POV of StakeValidator
(DCertPoolRetire
and DCertPoolRegister
). This leaves just the ones related to the delegation from the delegator's POV, which is the StakeValidator
POV:
DCertDelegRegKey StakingCredential
is the certificate for registering a stake address. In our case, a script stake address where StakingCredential
will correspond to our script's credential, i.e. the validator hash.
DCertDelegDeRegKey StakingCredential
is the certificate for de-registering a stake address.
DCertDelegDelegate StakingCredential PubKeyHash
is the certificate for delegating the StakingCredential
to the pool with the specified PubKeyHash
.
Last updated