If someone provides me with a payment address, how can I derive the staking address from the payment address?
This can be useful for example when we want to sent rewards to the people in return for staking to a pool.
Cardano Stack Exchange is a question and answer site for users and developers of the Cardano cryptocurrency ecosystem. It only takes a minute to sign up.
Sign up to join this communityIf someone provides me with a payment address, how can I derive the staking address from the payment address?
This can be useful for example when we want to sent rewards to the people in return for staking to a pool.
This only works if it's an address embedding the payment and stake credential. You can use cardano-address address inspect
locally. You could also use a tool like cardanoscan.io which when given an address to scan tells you the stake address associated as well.
Note that some addresses don't have stake addresses and other ones can have only pointers to stake registrations.
As Samuel said, the address in question must contain the staking part in the first place.
cardano-address uses IOG's implementation of bech32. Instead of using cardano-address you could also install bech32 instead and decode/encode the address.
$ addr=addr1qxkmuf2gqzsm5ejxm2amrwuq3pcc02cw6tttgsgqgafj46klskg5jjufdyf4znw8sjn37enwn5ge5l66qsx8srrpg3tq8du7us
$ echo $addr | ./bech32
01adbe254800a1ba6646dabbb1bb80887187ab0ed2d6b4410047532aeadf8591494b896913514dc784a71f666e9d119a7f5a040c780c614456
Now extract the last 57 bytes from the result as it is the staking address. Then you prefix that with the correct network tag (e0 for testnet and e1 for mainnet) and encode with bech32 to receive the staking address
$ echo "e1$(echo $addr | ./bech32 | tail -c 57)" | ./bech32 stake
stake1u9rfyvw5pkeherf56lzxjaqlpxs53fjghl4ft6w2x8wpnwchfeam3
On a side note, be aware of the existence of franken addresses. A constructed address which has the payment part of one wallet and the staking part of another. This way I could pretend I am the owner of the stake delegated to the pool.
Just for completeness, you can also use Haskell to decode the address into its components using a function like the one shown in the Plutus Pioneer Program.
tryReadStakeAddress :: String -> Maybe Plutus.StakingCredential
tryReadStakeAddress = show . Plutus.addressStakingCredential . tryReadAddress
tryReadAddress :: String -> Maybe Plutus.Address
tryReadAddress x = case deserialiseAddress AsAddressAny $ pack x of
Nothing -> Nothing
Just (AddressByron _) -> Nothing
Just (AddressShelley (ShelleyAddress _ p s)) -> Just Plutus.Address
{ Plutus.addressCredential = credentialLedgerToPlutus p
, Plutus.addressStakingCredential = stakeReferenceLedgerToPlutus s
}
credentialLedgerToPlutus :: Ledger.Credential a StandardCrypto -> Plutus.Credential
credentialLedgerToPlutus (ScriptHashObj (ScriptHash h)) = Plutus.ScriptCredential $ Plutus.ValidatorHash $ toBuiltin $ hashToBytes h
credentialLedgerToPlutus (KeyHashObj (KeyHash h)) = Plutus.PubKeyCredential $ Plutus.PubKeyHash $ toBuiltin $ hashToBytes h
stakeReferenceLedgerToPlutus :: Ledger.StakeReference StandardCrypto -> Maybe Plutus.StakingCredential
stakeReferenceLedgerToPlutus (StakeRefBase x) = Just $ StakingHash $ credentialLedgerToPlutus x
stakeReferenceLedgerToPlutus (StakeRefPtr (Ptr (SlotNo x) y z)) = Just $ StakingPtr (fromIntegral x) (fromIntegral y) (fromIntegral z)
stakeReferenceLedgerToPlutus StakeRefNull = Nothing