Splitting Shelley addresses into payment and stake

Motivation:

I was reading @HeptaSean’s post: Please use `cardano-cli transaction build` instead of `cardano-cli transaction build-raw`
And noticed that he had two different types of --tx-out addresses with one much shorter than the other. Also, I understand that providing only the payment address (without stake address) could be more private since payees would be unable to see the wallet’s total controlled stake on blockchain explorers.

Experimentation

In trying to understand how this works better, I read CIP-0019 document: CIPs/README.md at master · cardano-foundation/CIPs · GitHub

I then thought I could use the longer address in @HeptaSean’s post since I know there were transactions on that address.

I then tried to split this address, “addr1q89vv6r6e7040j7lm5m3s9c9cv7l0hdchwrwt62xm4v7h2df36408rhdrmchm7pxj8huuyz4jsgzqjllta5xfgrjysqsznluu4”, into its components.

bech32 <<< addr1q89vv6r6e7040j7lm5m3s9c9cv7l0hdchwrwt62xm4v7h2df36408rhdrmchm7pxj8huuyz4jsgzqjllta5xfgrjysqsznluu4

01cac6687acf9f57cbdfdd37181705c33df7ddb8bb86e5e946dd59eba9a98eaaf38eed1ef17df82691efce10559410204bff5f6864a0722401

CIP-0019 states that the first byte (first 2 characters in above hex output = 01) means:

PaymentKeyHash and StakeKeyHash on mainnet

So then I tried to create only the payment address as follows:
Remove the first 2 hex characters, then take the next 28 bytes (56 hex characters)

echo -n 'cac6687acf9f57cbdfdd37181705c33df7ddb8bb86e5e946dd59eba9a98eaaf38eed1ef17df82691efce10559410204bff5f6864a0722401' | head -c 56

cac6687acf9f57cbdfdd37181705c33df7ddb8bb86e5e946dd59eba9

Then recreate just the payment address but this time with ‘61’ as first 2 characters since CIP-0019 says this means:

PaymentKeyHash and no delegation part on mainnet

bech32 addr <<< '61cac6687acf9f57cbdfdd37181705c33df7ddb8bb86e5e946dd59eba9'

addr1v89vv6r6e7040j7lm5m3s9c9cv7l0hdchwrwt62xm4v7h2gpts87v

But cardanoscan doesn’t show the transactions that do exist at that address: Address addr1v89vv6r6e7040j7lm5m3s9c9cv7l0hdchwrwt62xm4v7h2gpts87v - Cardanoscan

To be clear, what I want to be able to do is take an address from a wallet like Daedalus, Yoroi etc. and only give out the payment address part.

Questions

Would someone please explain how to do this properly?

Is there a privacy benefit in handing out only payment addresses (without the stake address part)?

You have done everything right, but it doesn’t show any transactions, since those are associated with the address including stake key hash.

The delegated and un-delegated (often called “enterprise”) addresses are independent according to the Cardano network.

I only know Eternl also scanning (and showing in the receive tab) the undelegated versions. And also there, the support is really, really basic. You will probably want to protect everything on undelegated addresses from being used in normal transactions and then unlock and build transactions manually as needed.

Also observe that an address used in delegated form before is not really more private, since the fact that this payment key hash is associated with this stake key hash is already on the blockchain then. You will want to use undelegated versions of addresses, where the delegated version was never used and make sure that the delegated version will never be used.

2 Likes

So if I sent some Ada and/or native tokens to address: addr1v89vv6r6e7040j7lm5m3s9c9cv7l0hdchwrwt62xm4v7h2gpts87v

Will you be able to spend it with your key?

Will it show in your Daedalus or Yoroi wallet?

I would be able to then see my transaction sent using blockchain explorers but I wouldn’t know how much total stake the wallet controlled? Right?

Yes, but if I pick an unused address from my wallet and break out just the payment address as I did above then it will be more private? Won’t it? So long as I don’t send any other outputs to the combined form of this address with the stake key?

Another question: If the wallet is staked, will funds sent to the payment (without stake key) address contribute somehow to the amount staked by the wallet? I guess they won’t because there would be no way for the blockchain to know which stake key was associated?

Yes. To spend something on an address with a payment key hash as payment part, I need to give the public key (since the address only contains the hash) and a signature of the transaction by the private key. Since I have the key, I can do that.

(If the payment part would be a script hash, the script would have to be given with the transaction and everything the script demands would have to be fulfilled.)

I don’t think so, but I haven’t really tried. I really only know Eternl also scanning the undelegated address versions.

Given the constraints below about the delegated version being used, yes.

Yes, exactly that.

And yes, exactly, again. That’s exactly the reason for the second, stake part of addresses – to sum up the total stake for that stake part. If there is no stake part, that address does not contribute to any stake.

That’s also how so-called “franken”addresses work. You combine a payment part from one wallet with a stake part from another wallet. Then, I can spend with the first, but it contributes to the stake of the second.

1 Like

I think I understand better now. What was confusing me was that I had thought they were the same address if they had the same payment key hash.

I see now that depending on whether you combine that payment key hash with or without a stake key hash or even someone else’s stake key hash will all produce different addresses which can contain different collections of UTxOs. However, you can notice that addresses are all controlled by the same payment key if the first part of the address is identical (after the first byte). You can then confirm this by bech32 decoding the addresses.

Thanks for the explanation.

1 Like

Yes. As far as I know the blockchain itself uses the hex version, anyway. (I would do it if I want to save every byte.)

And you can also somehow see the identical parts in the BECH32 encoded form of addresses from the same wallet, but it will not be the the BECH32 of the stake address, since the boundaries are on different bits. (BECH32 encodes 5 bit blocks.)

1 Like