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

Extend cosmwasm-schema to be able to annotate the resultant JsonSchemas with Parameter/ReturnType/State tags. (Or similar) #1276

Closed
rtviii opened this issue Apr 20, 2022 · 8 comments
Milestone

Comments

@rtviii
Copy link
Contributor

rtviii commented Apr 20, 2022

Hi, This both a proposal and a question.

The problem: i'm trying to generate typescript bindings for cosmwasm contracts to speed up the development with our js package. In the ideal world, query and execute methods along with types would be transpiled directly from rust contract to typescript and that'd be the end of story.
In the short term though it'd be really nice to have the clarity as to which generated .json type corresponds to a method's parameter and which -- to its return type.

Currently

In terms of the cw-template and in the most basic case this would work as follows:

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
    GetCount {},                               
}

yields the following schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "QueryMsg",
  "anyOf": [
    {
      "type": "object",
      "required": [
        "get_count"
      ],
      "properties": {
        "get_count": {
          "type": "object"
        }
      },
      "additionalProperties": false
    }
  ]
}

Desirable

With "param/return type method tags" or whatever this might instead look like the following:

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] 
#[serde(rename_all = "snake_case")]
#[ XXX (method=query, "parameter")]             // <---- tag this (maybe something inside schemars or serde)?
pub enum QueryMsg {                                                              
    GetCount {},  
    GetOwner{}                             
}

yields the following schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "QueryMsg",
  "myCustomTag": {"typeSet": "query", "role":"parameter"},               // <--- now i know this type belongs to the query set
  "anyOf": [
    {
      "type": "object",
      "required": [
        "get_count"
      ],
      "properties": {
        "get_count": {
          "type": "object"
        }
      },
      "additionalProperties": false
    }
  ]
}

This is just one possible implementation, probably with lots of edge cases down the road -- i'd really love to hear what you guys think to this end. Perhaps this is better done as a custom schemars trait or a macro or a serde injection...

Implementation details aside, i think it'd be useful to have this additional reference/link between the schema files because the space of things that can be reconstructed (in typescript or other langs) from them right now is limited by its lack.

In general, i'd be very happy to contribute to any transpilation effort here.

Seeing as @webmaster128 wrote this bit -- would like to refer to your expertise on this. Please advise!

@rtviii
Copy link
Contributor Author

rtviii commented Apr 21, 2022

A few other things that can maybe be tied into this:

  • producing schemas for the Error types and tying them into the same overarching structure ( not yet clear what that is ).
  • deriving a custom Response schema for each method with its particular set of SubMsgs: Attributes,CosmosMsgs, Events etc. I'm still very much making sense of how it is put together, but it seems like all those sub-messages have JsonSchema already #[derived.

Example:

        Response::new()
        .add_attribute("method", "instantiate")
        .add_attribute("owner", info.sender)
        .add_attribute("count", msg.count)

would get translated into the valid version of

{
    "type": "object",
    "properties": {
        "method": "string",
        "owner": "Address",          // <--- maybe instead a json $ref to protocol://global-cosmwasm-typespace/Address
        "count": "int32"
    },
    "required": [...],
    ...
}

I guess according to this logic every type exposed to the user in cosmwasm needs a schema if it were to be $ref'ed? Not sure. That would still be pretty useful.

@rtviii
Copy link
Contributor Author

rtviii commented Apr 25, 2022

In particular:

* deriving a custom [Response](https://github.com/CosmWasm/cosmwasm/blob/main/packages/std/src/results/response.rs) schema for each method with its particular set of `SubMsgs`: `Attribute`s,`CosmosMsg`s, `Event`s etc. 

I think this can be done as a procedural macro.

I.e. for a given cosmwasm contract method, say try_modify_state_x which returns Response with 2 attributes, the macro would document the arguments and an object with 2 fields in schema/try_modify_state_x.json. I'll try to work out the assumption that both the args and the response's sub-messages are serializable.

Again, motivation being: it seems like a lot of data that is integrations-relevant that is returned by a given contract are Responses decorated with a particular set of sub messages. So, as far as all of the sub-messages for a particular Response are serializable (have the correct traits derived) the method can readily provide the JSONSchema for what it returns to be used in SDKs and off-chain integrations etc.

@pyramation
Copy link

hey @rtviii by chance are you using https://github.com/pyramation/cosmwasm-typescript-gen — if so, I think what you may be looking for (as a temporary solution) is what we're doing here https://github.com/public-awesome/stargaze-contracts/blob/main/contracts/sg721/examples/schema.rs#L20-L39

@rtviii
Copy link
Contributor Author

rtviii commented May 16, 2022

@pyramation love your work with ast's & macros in that package and postgres(unrelated). been meaning to take a look at the cosmwasm-typescript-gen for over a week now ever since somebody on the team brought it up. thanks a ton for putting in the work.

@webmaster128
Copy link
Member

@uint can you confirm if the core of this request is done in #1339? If yes, please close. Follow-up tickets can be created for anything that is left on the wishlist.

@webmaster128 webmaster128 added this to the 1.1.0 milestone Jul 12, 2022
@uint
Copy link
Contributor

uint commented Jul 12, 2022

@uint can you confirm if the core of this request is done in #1339? If yes, please close. Follow-up tickets can be created for anything that is left on the wishlist.

I think so, although we're doing it quite differently from what OP suggested.

From that wishlist, we don't (yet!) have a way of describing possible events a contract might emit, but it's going to happen.

For reference:

I think we can close this and let @rtviii reopen if he doesn't feel we addressed his problem.

@uint uint closed this as completed Jul 12, 2022
@rtviii
Copy link
Contributor Author

rtviii commented Jul 12, 2022

Awesome work!

@pyramation
Copy link

amazing! 👏🏻👏🏻👏🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants