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

which checksum for instantiate2_address()? #1948

Open
taitruong opened this issue Nov 15, 2023 · 4 comments
Open

which checksum for instantiate2_address()? #1948

taitruong opened this issue Nov 15, 2023 · 4 comments
Labels
Question ❓ User question

Comments

@taitruong
Copy link

Missing further explaination here for checksum:

/// pub fn execute(
/// deps: DepsMut,
/// env: Env,
/// info: MessageInfo,
/// msg: ExecuteMsg,
/// ) -> Result<Response, StdError> {
/// let canonical_creator = deps.api.addr_canonicalize(env.contract.address.as_str())?;
/// let checksum = HexBinary::from_hex("9af782a3a1bcbcd22dbb6a45c751551d9af782a3a1bcbcd22dbb6a45c751551d")?;
/// let salt = b"instance 1231";
/// let canonical_addr = instantiate2_address(&checksum, &canonical_creator, salt)
/// .map_err(|_| StdError::generic_err("Could not calculate addr"))?;
/// let addr = deps.api.addr_humanize(&canonical_addr)?;
///
/// # Ok(Default::default())
/// }
/// ```
pub fn instantiate2_address(

Like in our execute msg, we use code id's checksum when using instantiate2_address() for determining and storing address, before calling WasmMsg::Instantiate2. For WasmMsg::Instantiate2 only salt is required, so I assume somewhere it uses code id checksum as well for validating this?

Here's how our execute msg looks like:

// for creating a predictable nft contract using, using instantiate2, we need: checksum, creator, and salt:
// - using class id as salt for instantiating nft contract guarantees a) predictable address and b) uniqueness
// for this salt must be of length 32 bytes, so we use sha256 to hash class id
let mut hasher = Sha256::new();
hasher.update(class_id.as_bytes());
let salt = hasher.finalize().to_vec();
// Get the canonical address of the contract creator
let canonical_creator = deps.api.addr_canonicalize(env.contract.address.as_str())?;
// get the checksum of the contract we're going to instantiate
let CodeInfoResponse { checksum, .. } = deps
    .querier
    .query_wasm_code_info(CW721_CODE_ID.load(deps.storage)?)?;
let canonical_cw721_addr = instantiate2_address(&checksum, &canonical_creator, &salt)?;
let cw721_addr = deps.api.addr_humanize(&canonical_cw721_addr)?;

// Save classId <-> contract mappings.
CLASS_ID_TO_NFT_CONTRACT.save(deps.storage, class_id.clone(), &cw721_addr)?;
NFT_CONTRACT_TO_CLASS_ID.save(deps.storage, cw721_addr.clone(), &class_id)?;

let message = SubMsg::<T>::reply_on_success(
    WasmMsg::Instantiate2 {
        admin: None,
        code_id: CW721_CODE_ID.load(deps.storage)?,
        msg: self.init_msg(deps.as_ref(), &env, &class)?,
        funds: vec![],
        // Attempting to fit the class ID in the label field
        // can make this field too long which causes data
        // errors in the SDK.
        label: "ics-721 debt-voucher cw-721".to_string(),
        salt: salt.into(),
    },
    INSTANTIATE_CW721_REPLY_ID,
);

@DariuszDepta, maybe u can clarify this?

@DariuszDepta
Copy link
Member

Hi @taitruong, I will try to shed some more light on it ;-)

In real-life blockchain, after storing the contract code, the only way to learn the checksum is to get it via CodeInfoResponse structure, exactly like in your example.
After storing the contract code this checksum can be considered constant, but it is always a good pattern just to retrieve it before using instantiate2_address function.
How the checksum is calculated, what length it is - all these should be transparent, and users should not make any assumptions about this. Apparently the function instantiate2_address requires that the checksum length must be exactly 32 bytes long, but theses are internals. The guarantee is, that the checksum returned in CodeInfoResponse will fit the checksum argument in instantiate2_address function.

From the context of your post, when you mention code id for calculating the checksum, I am guessing that you would like to get the same predictable addresses in real-life blockchain and in tests?

In MultiTest we need to simulate the real-blockchain environment, it means there is no way to generate the same contract's code checksum like in real chain. So the simplest solution was to generate checksum based on the code id. As this solution is not perfect, and may not fit all user cases, we have provided a possibility to develop your own checksum generator used later in MultiTest. Please refer this article to learn more about providing custom checksum generator to MultiTest.

Please be aware, that default checkum returned in CodeInfoResponse in MultiTest is exactly 32 bytes long, and fits the instantiate2_address function. When generating your own checksum, please keep it also 32 bytes long to avoid problems with calling instantiate2_address. There is some more freedom in tests, but it should be used carefully ;-).

I hope this helps a little bit ;-).
If you have any other concerns, please do not hesitate to let us know.

@DariuszDepta
Copy link
Member

Hi @taitruong, can we close this issue already?

@taitruong
Copy link
Author

@DariuszDepta, thx for in-depth info! Just want to make sure: is WasmMsg::Instantiate2 using code as check sum?
I guess so, otherwise I would get a different address compared to instantiate2_address(). Right?

@DariuszDepta
Copy link
Member

Hi @taitruong, I confirm, currently in *MultiTest the checksum used while handling Wasm::Instantiate2 message uses contract's code id, the precise algorithm is shown here: https://github.com/CosmWasm/cw-multi-test/blob/4bc617f899a7f8d4257e9633d4a0340628dfee61/src/checksums.rs#L21-L27
As already said, you are free to adjust it by implementing your own ChecksumGenerator if needed ;-)

@chipshort chipshort added the Question ❓ User question label Apr 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question ❓ User question
Projects
None yet
Development

No branches or pull requests

3 participants