public-awesome / cw-ics721

CosmWasm IBC NFT Transfers
MIT License
56 stars 30 forks source link

receive callback fix: query NFT contract from storage (and not instantiate2) #98

Closed taitruong closed 1 week ago

taitruong commented 1 month ago

UPDATE: most code changes was done in e2e tests. Huge shoutout to @magiodev! code for fix is quite small. We felt the need to refactor e2e tests and add more and deeper tests using Go.


For receive callback, nft contract needs to be passed. Before this fix, it was using instantiated2 for retrieving nft contract. As part of instantiate2 it uses cw721's code id for predicting nft contract address:

            let cw721_code_id = CW721_CODE_ID.load(deps.storage)?;
            // 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(local_class_id.as_bytes());
            let salt = hasher.finalize().to_vec();

            get_instantiate2_address(deps, env.contract.address.as_str(), &salt, cw721_code_id)

But if cw721 code id changes, then it returns wrong address. In this case whole TX fails and NFT gets reverted/returned to sender.

Fix is getting address from CLASS_ID_AND_NFT_CONTRACT_INFO storage:

            Ok(CLASS_ID_AND_NFT_CONTRACT_INFO
                .load(deps.storage, &local_class_id)?
                .address)