10

are there any methods or tools?

such as parachain id is 1000.

how to get this parachain's sovereignAccount

5 Answers 5

10

UPDATE: shawn's utils website has a "Para ID" to Address utility.

Here is parachain sovereign account 2000 (the AcountId32):

0x70617261 + d0070000 + 000000000000000000000000000000000000000000000000

0x70617261 = b"para" (up/down) or 0x7369626c = b"sibl" (side-to-side)

d0070000 = scale encoded number 2000

You can see the scale encoding of a u32 by typing the number into collatorSelection/setDesiredCandidates and looking at the encoded call details on the bottom right by max that is the encoded version of 2000.

enter image description here

To copy and paste:

1000: 0x70617261e8030000000000000000000000000000000000000000000000000000

2000: 0x70617261d0070000000000000000000000000000000000000000000000000000

2001: 0x70617261d1070000000000000000000000000000000000000000000000000000

2002: 0x70617261d2070000000000000000000000000000000000000000000000000000

(That's also enough examples that you could guess the rest. I do think that we need an easy way to get these from polkadot-js maybe from the parachain screen? - PRs welcome!)

If you want a normal polkadot/kusama address then you can use the "AccountId to Hex" at https://www.shawntabrizi.com/substrate-js-utilities/ - paste in the above on the right hand side as the hex and you will get the address calculated. For example, for 1000 parachain id it returns 5Ec4AhPZk8STuex8Wsi9TwDtJQxKqzPJRCH7348Xtcs9vZLJ

2
  • nice job.thanks
    – linus NG
    Commented Mar 28, 2022 at 9:41
  • subkey inspect allows to get the public account in different formats Commented Jun 13, 2022 at 18:30
8

Id (aka ParaId) implements into_account_id(), as described here. The code translates to ("para", id).encode(), then decoded as a 32 byte account id, with trailing zeros if need be.

I am not aware of any tools, but probably it would be very easy to make one, or manually check them.

3

Now, we have another choice Subalfred, a CLI toolbox.

# Sovereign address on relaychain.
subalfred key --type parachain 2000
public-key 0x70617261d0070000000000000000000000000000000000000000000000000000 ParaId(2000)
Substrate 5Ec4AhPUwPeyTFyuhGuBbD224mY85LKLMSqSSo33JYWCazU4

# Sovereign address on sibling chain.
subalfred key --type sibling 2000
public-key 0x7369626cd0070000000000000000000000000000000000000000000000000000 SiblId(2000)
Substrate 5Eg2fntJ27qsari4FGrGhrMqKFDRnkNSR6UshkZYBGXmSuC8

# Note that, if you are on Moonbeam-link chain, remove 24 trailing zeros from the public-key.
public-key 0x7369626cd0070000000000000000000000000000000000000000000000000000 SiblId(2000)
public-key 0x7369626cd0070000000000000000000000000000 SiblId(2000)

# Subalfred will detect if this is a sovereign address automatically.
subalfred key 5Eg2fntJ27qsari4FGrGhrMqKFDRnkNSR6UshkZYBGXmSuC8
public-key 0x7369626cd0070000000000000000000000000000000000000000000000000000 SiblId(2000)
Substrate 5Eg2fntJ27qsari4FGrGhrMqKFDRnkNSR6UshkZYBGXmSuC8

For more details, check the https://subalfred.hack.ink/user/cli/key.html.

2

The answers above are brilliant, but just in case is useful for other devs I want to share a code snippet to calculate the Sovereign Account in Rust.

use scale::Encode;
use sp_core::{crypto::{Ss58AddressFormatRegistry, Ss58Codec}, sr25519::Pair};
use sp_runtime::{MultiSigner};

let sovereign_account_str = calculate_sovereign_account::<Pair>(para_id)?;

fn calculate_sovereign_account<Pair>(
    para_id: u32,
) -> Result<String, Box<dyn std::error::Error>>
where
    Pair: sp_core::Pair,
    Pair::Public: Into<MultiSigner>,
{
    // Scale encoded para_id
    let id = RococoId(para_id);
    let encoded_id = hex::encode(id.encode());

    // Prefix para or sibl
    let prefix = hex::encode("para"); 

    // Join both strings and the 0x at the beginning
    let encoded_key = "0x".to_owned() + &prefix + &encoded_id;

    // Fill the rest with 0s
    let public_str = format!("{:0<width$}", encoded_key, width = 64 + 2);

    // Convert hex public key to ss58 address
    let public = array_bytes::hex2bytes(&public_str).expect("Failed to convert hex to bytes");
    let public_key = Pair::Public::try_from(&public)
        .map_err(|_| "Failed to construct public key from given hex")?;

    Ok(public_key.to_ss58check_with_version(Ss58AddressFormatRegistry::SubstrateAccount.into()))
}
1

Using python's scalecodec (py-scale-codec), you can get it like:

from scalecodec.base import ScaleBytes
from scalecodec.types import U32
from scalecodec.utils.ss58 import ss58_encode


def get_parachain_sovereign_account(para_id, chain_type='para'):
    scale_encoded = chain_type.encode().hex()
    scale_encoded += U32(ScaleBytes(bytearray())).encode(para_id).to_hex()[2:]
    public_key = f"0x{scale_encoded + ''.join(['0' * (64 - len(scale_encoded))])}"
    print(
        f'\t  Account ID:\t{public_key}\n' + \
        f'\tSS58 Address:\t{ss58_encode(public_key)}'
    )

Then...

get_parachain_sovereign_account(1000)
>>>
      Account ID:   0x70617261e8030000000000000000000000000000000000000000000000000000
    SS58 Address:   5Ec4AhPZk8STuex8Wsi9TwDtJQxKqzPJRCH7348Xtcs9vZLJ

get_parachain_sovereign_account(2000)
>>>
      Account ID:   0x70617261d0070000000000000000000000000000000000000000000000000000
    SS58 Address:   5Ec4AhPUwPeyTFyuhGuBbD224mY85LKLMSqSSo33JYWCazU4

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.