public-awesome / cw-nfts

Examples and helpers to build NFT contracts on CosmWasm
Apache License 2.0
188 stars 180 forks source link

`cosmwasm-schema` Properly handle cw721 extension messages #165

Closed MbBrainz closed 2 months ago

MbBrainz commented 3 months ago

Both query and execute extensions on cw721 are not properly serialized. You can see what happens when you add the schema to this contract and to query the contract for the extension (try for token-2). The returned data is correct(as shown in the json output), but its not properly parsed using the schema and therefore it shows as Null in the Return Output -> Your Schema tab. link to the contract on celat.one

For the messages below i get the attached schema:

#[cw_serde]
#[derive(ExecuteFns)]
pub enum MagotchiExecuteExtension {
    /// Hatch a new magotchi, you need to feed it from now on
    Hatch { token_id: String },
    /// Feed the magotchi, resetting its health
    Feed { token_id: String },
    /// Reap all dead magotchis, sending it to the graveyard. If option tokens is provided, only those tokens will be reaped, otherwise all dead tokens will be reaped (might fail if there are too many dead tokens to reap in one go)
    Reap { tokens: Option<Vec<String>> },
    /// Set the Config of the contract, including the daily feeding cost, the maximum days without food and the day length
    UpdateConfig { config: PartialConfig },
}

impl CustomMsg for MagotchiExecuteExtension {}
#[cw_serde]
#[derive(QueryResponses, QueryFns)]
pub enum MagotchiQueryExtension {
    /// Returns the health of the magotchi
    #[returns(HealthResponse)]
    Health { token_id: String },
    /// Returns the cost of feeding the magotchi
    #[returns(FeedingCostResponse)]
    FeedingCost { token_id: String },
    /// Returns the Config of the contract, including the daily feeding cost, the maximum days without food and the day length
    #[returns(Config)]
    Config {},
    /// Return the birthday of the magotchi
    #[returns(Timestamp)]
    HatchedAt { token_id: String },

    /// Return the dying day of the magotchi
    #[returns(Timestamp)]
    DeathTime { token_id: String },

    /// Return if the magotchi is hatched
    #[returns(bool)]
    IsHatched { token_id: String },

    /// Return the live state of the magotchi
    #[returns(Gotchi)]
    GotchiState { token_id: String },
}

impl CustomMsg for MagotchiQueryExtension {}

pub type ExecuteMsg = cw721_base::ExecuteMsg<Extension, ExecuteExtension>;
pub type QueryMsg = cw721_base::QueryMsg<QueryExtension>;

fn main() {
    write_api! {
        instantiate: InstantiateMsg, // default cw721_base Instantiate
        execute: ExecuteMsg,
        query: QueryMsg,

    }
}

cw721-gotchi.json

webmaster128 commented 3 months ago

Is this ticket meant to go to https://github.com/CosmWasm/cw-nfts where cw721 is maintained? I can transfer if you agree

MbBrainz commented 2 months ago

@webmaster128 this ticket is about the malfunctioning of Cosmwasm_schema when it comes to extensions. These extensions are a present in the cw721 code, but are not unique to it.

uint commented 2 months ago

Hi! I'm the creator of the relevant macros in cosmwasm-schema.

What you're asking for, as I understand it, is possible in cosmwasm-schema as long as you use the nested syntax as found in the docs. To the best of my knowledge, this does work with generics too.

After a brief look at the codebase here, it looks like QueryMsg follows a different pattern, and then handwaves schema generation. This should be fixable right here, in this repo.

uint commented 2 months ago

BTW, the doc comments state the extension query is a dummy. Is that meant to be queried? I don't understand this codebase.

After looking at this more, I don't think the snippets you provided are how "metadata extensions" are meant to be used. See here and here.

I suspect what you might want to do instead in your project to provide both Cw721 and custom queries is something like:

#[cw_serde]
#[derive(QueryResponses)]
#[serde(untagged)]
#[query_responses(nested)]
pub enum QueryMsg {
    Cw721(cw721_base::QueryMsg<Something>),
    MyOtherQueries(MagotchiQueryExtension),
}

#[cw_serde]
#[derive(QueryResponses, QueryFns)]
pub enum MagotchiQueryExtension {
    /// Returns the health of the magotchi
    #[returns(HealthResponse)]
    Health { token_id: String },

    // ...
}
uint commented 2 months ago

I'm closing this, but if there's something I missed, feel free to reopen!