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

feat(ContractSpec): add jsonSchema method #889

Merged
merged 6 commits into from
Dec 14, 2023

Conversation

willemneal
Copy link
Member

@willemneal willemneal commented Dec 7, 2023

Replaces js-soroban-client.

Example of proposed schema using custom types contract from CLI
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "U32": {
      "type": "integer",
      "minimum": 0,
      "maximum": 4294967295
    },
    "I32": {
      "type": "integer",
      "minimum": -2147483648,
      "maximum": 2147483647
    },
    "U64": {
      "type": "string",
      "pattern": "^([1-9][0-9]*|0)$",
      "minLength": 1,
      "maxLength": 20
    },
    "I64": {
      "type": "string",
      "pattern": "^(-?[1-9][0-9]*|0)$",
      "minLength": 1,
      "maxLength": 21
    },
    "U128": {
      "type": "string",
      "pattern": "^([1-9][0-9]*|0)$",
      "minLength": 1,
      "maxLength": 39
    },
    "I128": {
      "type": "string",
      "pattern": "^(-?[1-9][0-9]*|0)$",
      "minLength": 1,
      "maxLength": 40
    },
    "U256": {
      "type": "string",
      "pattern": "^([1-9][0-9]*|0)$",
      "minLength": 1,
      "maxLength": 78
    },
    "I256": {
      "type": "string",
      "pattern": "^(-?[1-9][0-9]*|0)$",
      "minLength": 1,
      "maxLength": 79
    },
    "Address": {
      "type": "string",
      "format": "address",
      "description": "Address can be a public key or contract id"
    },
    "ScString": {
      "type": "string",
      "description": "ScString is a string"
    },
    "ScSymbol": {
      "type": "string",
      "description": "ScString is a string"
    },
    "DataUrl": {
      "type": "string",
      "pattern": "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=)?$"
    },
    "Test": {
      "description": "This is from the rust doc above the struct Test",
      "properties": {
        "a": {
          "$ref": "#/definitions/U32"
        },
        "b": {
          "type": "boolean"
        },
        "c": {
          "$ref": "#/definitions/ScSymbol"
        },
        "additionalProperties": false
      },
      "required": [
        "a",
        "b",
        "c"
      ],
      "type": "object"
    },
    "SimpleEnum": {
      "oneOf": [
        {
          "tag": "First"
        },
        {
          "tag": "Second"
        },
        {
          "tag": "Third"
        }
      ]
    },
    "RoyalCard": {
      "oneOf": [
        {
          "description": "",
          "title": "Jack",
          "enum": [
            11
          ],
          "type": "number"
        },
        {
          "description": "",
          "title": "Queen",
          "enum": [
            12
          ],
          "type": "number"
        },
        {
          "description": "",
          "title": "King",
          "enum": [
            13
          ],
          "type": "number"
        }
      ]
    },
    "TupleStruct": {
      "type": "array",
      "items": [
        {
          "$ref": "#/definitions/Test"
        },
        {
          "$ref": "#/definitions/SimpleEnum"
        }
      ],
      "minItems": 2,
      "maxItems": 2
    },
    "ComplexEnum": {
      "oneOf": [
        {
          "tag": "Struct",
          "values": [
            {
              "$ref": "#/definitions/Test"
            }
          ]
        },
        {
          "tag": "Tuple",
          "values": [
            {
              "$ref": "#/definitions/TupleStruct"
            }
          ]
        },
        {
          "tag": "Enum",
          "values": [
            {
              "$ref": "#/definitions/SimpleEnum"
            }
          ]
        },
        {
          "tag": "Asset",
          "values": [
            {
              "$ref": "#/definitions/Address"
            },
            {
              "$ref": "#/definitions/I128"
            }
          ]
        },
        {
          "tag": "Void"
        }
      ]
    },
    "hello": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "hello": {
              "$ref": "#/definitions/ScSymbol"
            }
          },
          "type": "object",
          "required": [
            "hello"
          ]
        }
      }
    },
    "woid": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {},
          "type": "object"
        }
      }
    },
    "val": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {},
          "type": "object"
        }
      }
    },
    "u32_fail_on_even": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "u32_": {
              "$ref": "#/definitions/U32"
            }
          },
          "type": "object",
          "required": [
            "u32_"
          ]
        }
      }
    },
    "u32_": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "u32_": {
              "$ref": "#/definitions/U32"
            }
          },
          "type": "object",
          "required": [
            "u32_"
          ]
        }
      }
    },
    "i32_": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "i32_": {
              "$ref": "#/definitions/I32"
            }
          },
          "type": "object",
          "required": [
            "i32_"
          ]
        }
      }
    },
    "i64_": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "i64_": {
              "$ref": "#/definitions/I64"
            }
          },
          "type": "object",
          "required": [
            "i64_"
          ]
        }
      }
    },
    "strukt_hel": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "strukt": {
              "$ref": "#/definitions/Test"
            }
          },
          "type": "object",
          "required": [
            "strukt"
          ]
        }
      },
      "description": "Example contract method which takes a struct"
    },
    "strukt": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "strukt": {
              "$ref": "#/definitions/Test"
            }
          },
          "type": "object",
          "required": [
            "strukt"
          ]
        }
      }
    },
    "simple": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "simple": {
              "$ref": "#/definitions/SimpleEnum"
            }
          },
          "type": "object",
          "required": [
            "simple"
          ]
        }
      }
    },
    "complex": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "complex": {
              "$ref": "#/definitions/ComplexEnum"
            }
          },
          "type": "object",
          "required": [
            "complex"
          ]
        }
      }
    },
    "addresse": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "addresse": {
              "$ref": "#/definitions/Address"
            }
          },
          "type": "object",
          "required": [
            "addresse"
          ]
        }
      }
    },
    "bytes": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "bytes": {
              "$ref": "#/definitions/DataUrl"
            }
          },
          "type": "object",
          "required": [
            "bytes"
          ]
        }
      }
    },
    "bytes_n": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "bytes_n": {
              "$ref": "#/definitions/DataUrl",
              "maxLength": 9
            }
          },
          "type": "object",
          "required": [
            "bytes_n"
          ]
        }
      }
    },
    "card": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "card": {
              "$ref": "#/definitions/RoyalCard"
            }
          },
          "type": "object",
          "required": [
            "card"
          ]
        }
      }
    },
    "boolean": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "boolean": {
              "type": "boolean"
            }
          },
          "type": "object",
          "required": [
            "boolean"
          ]
        }
      }
    },
    "not": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "boolean": {
              "type": "boolean"
            }
          },
          "type": "object",
          "required": [
            "boolean"
          ]
        }
      },
      "description": "Negates a boolean value"
    },
    "i128": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "i128": {
              "$ref": "#/definitions/I128"
            }
          },
          "type": "object",
          "required": [
            "i128"
          ]
        }
      }
    },
    "u128": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "u128": {
              "$ref": "#/definitions/U128"
            }
          },
          "type": "object",
          "required": [
            "u128"
          ]
        }
      }
    },
    "multi_args": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "a": {
              "$ref": "#/definitions/U32"
            },
            "b": {
              "type": "boolean"
            }
          },
          "type": "object",
          "required": [
            "a",
            "b"
          ]
        }
      }
    },
    "map": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "map": {
              "type": "array",
              "items": {
                "type": "array",
                "items": [
                  {
                    "$ref": "#/definitions/U32"
                  },
                  {
                    "type": "boolean"
                  }
                ],
                "minItems": 2,
                "maxItems": 2
              }
            }
          },
          "type": "object",
          "required": [
            "map"
          ]
        }
      }
    },
    "vec": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "vec": {
              "type": "array",
              "items": {
                "$ref": "#/definitions/U32"
              }
            }
          },
          "type": "object",
          "required": [
            "vec"
          ]
        }
      }
    },
    "tuple": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "tuple": {
              "type": "array",
              "items": [
                {
                  "$ref": "#/definitions/ScSymbol"
                },
                {
                  "$ref": "#/definitions/U32"
                }
              ],
              "minItems": 2,
              "maxItems": 2
            }
          },
          "type": "object",
          "required": [
            "tuple"
          ]
        }
      }
    },
    "option": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "option": {
              "$ref": "#/definitions/U32"
            }
          },
          "type": "object"
        }
      },
      "description": "Example of an optional argument"
    },
    "u256": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "u256": {
              "$ref": "#/definitions/U256"
            }
          },
          "type": "object",
          "required": [
            "u256"
          ]
        }
      }
    },
    "i256": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "i256": {
              "$ref": "#/definitions/I256"
            }
          },
          "type": "object",
          "required": [
            "i256"
          ]
        }
      }
    },
    "string": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "string": {
              "$ref": "#/definitions/ScString"
            }
          },
          "type": "object",
          "required": [
            "string"
          ]
        }
      }
    },
    "tuple_strukt": {
      "additionalProperties": false,
      "contractMethod": "view",
      "properties": {
        "args": {
          "additionalProperties": false,
          "properties": {
            "tuple_strukt": {
              "$ref": "#/definitions/TupleStruct"
            }
          },
          "type": "object",
          "required": [
            "tuple_strukt"
          ]
        }
      }
    }
  }
}

Also add tests that generate input data based on JSON schema

Copy link

New dependencies detected. Learn more about Socket for GitHub ↗︎

Packages Version New capabilities Transitives Size Publisher
json-schema-faker 0.5.4 eval, network, filesystem, environment +5 3.68 MB pateketrueke

Also add tests that generate input data based on JSON schema
Copy link
Contributor

@Shaptic Shaptic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coupla minor comments, and this might need a yarn fmt, but this is an awesome feature addition! 👏

(ooh can you add a changelog entry as well?)

src/contract_spec.ts Outdated Show resolved Hide resolved
src/contract_spec.ts Outdated Show resolved Hide resolved
src/contract_spec.ts Outdated Show resolved Hide resolved
src/contract_spec.ts Show resolved Hide resolved
src/contract_spec.ts Outdated Show resolved Hide resolved
test/unit/spec/contract_spec.ts Outdated Show resolved Hide resolved
Copy link

socket-security bot commented Dec 13, 2023

👍 Dependency issues cleared. Learn more about Socket for GitHub ↗︎

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

Ignoring: jsonpath-plus@7.2.0, json-schema-faker@0.5.4, json-schema-ref-parser@6.1.0

Next steps

Take a deeper look at the dependency

Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support [AT] socket [DOT] dev.

Remove the package

If you happen to install a dependency that Socket reports as Known Malware you should immediately remove it and select a different dependency. For other alert types, you may may wish to investigate alternative packages or consider if there are other ways to mitigate the specific risk posed by the dependency.

Mark a package as acceptable risk

To ignore an alert, reply with a comment starting with @SocketSecurity ignore followed by a space separated list of package-name@version specifiers. e.g. @SocketSecurity ignore foo@1.0.0 bar@* or ignore all packages with @SocketSecurity ignore-all

@willemneal
Copy link
Member Author

Thanks for the feedback there was a lot of cleanup to do.

Is it okay that jsonschema-faker is a dev dep?

package.json Outdated Show resolved Hide resolved
@Shaptic
Copy link
Contributor

Shaptic commented Dec 14, 2023

@SocketSecurity ignore jsonpath-plus@7.2.0
@SocketSecurity ignore json-schema-faker@0.5.4
@SocketSecurity ignore json-schema-ref-parser@6.1.0

@Shaptic Shaptic merged commit dc07e03 into stellar:master Dec 14, 2023
7 of 8 checks passed
@chadoh chadoh deleted the feat/json_schema branch March 18, 2024 18:19
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

Successfully merging this pull request may close these issues.

2 participants