CosmWasm / ts-codegen

Convert your CosmWasm smart contracts into dev-friendly TypeScript classes so you can focus on shipping code.
https://cosmology.zone/products/ts-codegen
Apache License 2.0
116 stars 29 forks source link

Tuple-like EntryPointMsg variants incorrenctly generated #101

Closed adairrr closed 1 year ago

adairrr commented 1 year ago

For tuple-like enum variants, the types are incorrectly generated.

Example:

enum ExecuteMsg {
  UpdateOwnership(::cw_ownable::Action),
}

should generate msg-composer:

export interface AnsHostMessage {
...
  updateOwnership: (funds?: Coin[]) => MsgExecuteContractEncodeObject
...
}

export class AnsHostMessageComposer implements AnsHostMessage {
...
updateOwnership = (action: Action, funds?: Coin[]): MsgExecuteContractEncodeObject => {  
  return {  
    typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract',  
    value: MsgExecuteContract.fromPartial({  
      sender: this.sender,  
      contract: this.contractAddress,  
      msg: toUtf8(  
        JSON.stringify({  
          update_ownership: action,  
        })  
      ),  
      funds,  
    }),  
  }  
}
...
}

and msg-builder:

static updateOwnership = (action: Action): ExecuteMsg => {  
  return {  
    update_ownership: action,  
  }  
}

Technically it should generate the parameter as:

updateOwnership: (action: CamelCasedProperties<Action>, funds?: Coin[])

And the clients:

updateOwnership = async (  
action: Action,
  fee: number | StdFee | 'auto' = 'auto',  
  memo?: string,  
  funds?: Coin[]  
)
adairrr commented 1 year ago

Schema snippets:

{
  "contract_name": "abstract-ans-host",
  "contract_version": "0.14.0",
  "idl_version": "1.0.0",
  "instantiate": {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "InstantiateMsg",
    "description": "AnsHost Instantiate msg",
    "type": "object",
    "additionalProperties": false
  },
  "execute": {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "ExecuteMsg",
    "description": "AnsHost Execute msg",
    "oneOf": [
      {
        "description": "Update the contract's ownership. The `action` to be provided can be either to propose transferring ownership to an account, accept a pending ownership transfer, or renounce the ownership permanently.",
        "type": "object",
        "required": [
          "update_ownership"
        ],
        "properties": {
          "update_ownership": {
            "$ref": "#/definitions/Action"
          }
        },
        "additionalProperties": false
      }
    ],
    "definitions": {
      "Action": {
        "description": "Actions that can be taken to alter the contract's ownership",
        "oneOf": [
          {
            "description": "Propose to transfer the contract's ownership to another account, optionally with an expiry time.\n\nCan only be called by the contract's current owner.\n\nAny existing pending ownership transfer is overwritten.",
            "type": "object",
            "required": [
              "transfer_ownership"
            ],
            "properties": {
              "transfer_ownership": {
                "type": "object",
                "required": [
                  "new_owner"
                ],
                "properties": {
                  "expiry": {
                    "anyOf": [
                      {
                        "$ref": "#/definitions/Expiration"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "new_owner": {
                    "type": "string"
                  }
                },
                "additionalProperties": false
              }
            },
            "additionalProperties": false
          },
          {
            "description": "Accept the pending ownership transfer.\n\nCan only be called by the pending owner.",
            "type": "string",
            "enum": [
              "accept_ownership"
            ]
          },
          {
            "description": "Give up the contract's ownership and the possibility of appointing a new owner.\n\nCan only be invoked by the contract's current owner.\n\nAny existing pending ownership transfer is canceled.",
            "type": "string",
            "enum": [
              "renounce_ownership"
            ]
          }
        ]
      },
      "Expiration": {
        "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)",
        "oneOf": [
          {
            "description": "AtHeight will expire when `env.block.height` >= height",
            "type": "object",
            "required": [
              "at_height"
            ],
            "properties": {
              "at_height": {
                "type": "integer",
                "format": "uint64",
                "minimum": 0.0
              }
            },
            "additionalProperties": false
          },
          {
            "description": "AtTime will expire when `env.block.time` >= time",
            "type": "object",
            "required": [
              "at_time"
            ],
            "properties": {
              "at_time": {
                "$ref": "#/definitions/Timestamp"
              }
            },
            "additionalProperties": false
          },
          {
            "description": "Never will never expire. Used to express the empty variant",
            "type": "object",
            "required": [
              "never"
            ],
            "properties": {
              "never": {
                "type": "object",
                "additionalProperties": false
              }
            },
            "additionalProperties": false
          }
        ]
      },
      "Timestamp": {
        "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```",
        "allOf": [
          {
            "$ref": "#/definitions/Uint64"
          }
        ]
      },
      "Uint64": {
        "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```",
        "type": "string"
      }
    }
  },
  "query": {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "QueryMsg",
    "description": "AnsHost smart-query",
    "additionalProperties": false
  },
  "migrate": {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "MigrateMsg",
    "type": "object",
    "additionalProperties": false
  },
  "sudo": null,
  "responses": {
    "ownership": {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "title": "Ownership_for_String",
      "description": "The contract's ownership info",
      "type": "object",
      "properties": {
        "owner": {
          "description": "The contract's current owner. `None` if the ownership has been renounced.",
          "type": [
            "string",
            "null"
          ]
        },
        "pending_expiry": {
          "description": "The deadline for the pending owner to accept the ownership. `None` if there isn't a pending ownership transfer, or if a transfer exists and it doesn't have a deadline.",
          "anyOf": [
            {
              "$ref": "#/definitions/Expiration"
            },
            {
              "type": "null"
            }
          ]
        },
        "pending_owner": {
          "description": "The account who has been proposed to take over the ownership. `None` if there isn't a pending ownership transfer.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "additionalProperties": false,
      "definitions": {
        "Expiration": {
          "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)",
          "oneOf": [
            {
              "description": "AtHeight will expire when `env.block.height` >= height",
              "type": "object",
              "required": [
                "at_height"
              ],
              "properties": {
                "at_height": {
                  "type": "integer",
                  "format": "uint64",
                  "minimum": 0.0
                }
              },
              "additionalProperties": false
            },
            {
              "description": "AtTime will expire when `env.block.time` >= time",
              "type": "object",
              "required": [
                "at_time"
              ],
              "properties": {
                "at_time": {
                  "$ref": "#/definitions/Timestamp"
                }
              },
              "additionalProperties": false
            },
            {
              "description": "Never will never expire. Used to express the empty variant",
              "type": "object",
              "required": [
                "never"
              ],
              "properties": {
                "never": {
                  "type": "object",
                  "additionalProperties": false
                }
              },
              "additionalProperties": false
            }
          ]
        },
        "Timestamp": {
          "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```",
          "allOf": [
            {
              "$ref": "#/definitions/Uint64"
            }
          ]
        },
        "Uint64": {
          "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```",
          "type": "string"
        }
      }
    }
  }
}
adairrr commented 1 year ago

This should have been a known issue due to:


-   bank = async (): Promise<BankResponse> => {
+   bank = async (bankMsg: BankMsg): Promise<BankResponse> => {
      return this.client.queryContractSmart(this.contractAddress, {
-       bank: {}
+       bank: bankMsg
      });
    };
    custom = async (): Promise<CustomResponse> => {
      return this.client.queryContractSmart(this.contractAddress, {
        custom: {}
      });
    };
-   staking = async (): Promise<StakingResponse> => {
+   staking = async (stakingMsg: StakingMsg): Promise<StakingResponse> => {
      return this.client.queryContractSmart(this.contractAddress, {
-       staking: {}
+       staking: stakingMsg
      });
    };
-   distribution = async (): Promise<DistributionResponse> => {
+   distribution = async (distributionMsg: DistributionMsg): Promise<DistributionResponse> => {
      return this.client.queryContractSmart(this.contractAddress, {
-       distribution: {}
+       distribution: distributionMsg
      });
    };
-   wasm = async (): Promise<WasmResponse> => {
+   wasm = async (wasmMsg: WasmMsg): Promise<WasmResponse> => {
      return this.client.queryContractSmart(this.contractAddress, {
-       wasm: {}
+       wasm: wasmMsg
      });
    };
  }