JoinSEEDS / seeds_light_wallet

http://www.joinseeds.earth/
MIT License
42 stars 22 forks source link

Master Token List Schema #1919

Closed chuck-h closed 2 weeks ago

chuck-h commented 2 years ago

1880 introduced a JSON schema as a tool for validating token metadata. This metadata is used in LW primarily to manage UI presentation of the currency cards.

Token metadata is imported to LW as JSON from the tmastr.seeds smart contract. Metadata should never fail validation in LW because it should have been vetted prior to being approved in the tmastr.seeds contract tables. It is not practical for the smart contract to perform validation itself (due to large RAM requirement for JSON libraries and indeterminate execution time). Responsibility for ensuring the metadata for a newly added token is valid falls on (a) the software/UI used by the token submitter to "apply for" registration on the tmastr.seeds contract, and (b) the software/UI used by the curator to "approve" the token for a "use case". (For example, "visible in the Light Wallet" is a use case in this context.)

The process of validation should be consistent across metadata submission, approval, and usage contexts which are currently implemented on different platforms. The authoritative location for the validation schema could have been selected as any reasonably reliable and secure publicly-accessible storage (e.g. as an asset in the LW github repo); the decision was to place it on-chain in the tmastr.seeds contract.

JSON schema is quite an expressive and powerful validation language, but only elementary features have been employed in the tmastr.seeds data table.

  {
    "$schema": "http://json-schema.org/draft-04/schema#",
    "$id": "https://github.com/chuck-h/seeds-smart-contracts/blob/feature/master_token_list/assets/token_schema.json",
    "title": "token metadata",
    "description": "This document holds descriptive metadata (e.g. logo image) for cryptotokens used in the Seeds ecosystem",
    "type": "object",
    "properties": {
        "chain": {
            "description": "blockchain name",
            "type": "string",
            "enum": ["Telos","EOS","Wax"]
        },
        "symbol": {
            "description": "symbol ('ticker')",
            "type": "string",
            "minLength":1,
            "maxlength":7
        },
        "account": {
            "description": "account holding token contract",
            "type": "string",
            "minLength":3,
            "maxlength":13
        },
        "name": {
            "description": "short name of the token",
            "type": "string",
            "minLength":3,
            "maxlength":32
        },
        "logo": {
            "description": "url pointing to lo-res logo image",
            "type": "string",
            "minLength":3,
            "maxlength":128
        },
        "logo_lg": {
            "description": "url pointing to hi-res logo image",
            "type": "string",
            "minLength":3,
            "maxlength":128
        },
        "bg_image": {
            "description": "url pointing to card background image",
            "type": "string",
            "minLength":3,
            "maxlength":128
        },
        "subtitle": {
            "description": "wallet balance subtitle",
            "type": "string",
            "minLength":3,
            "maxlength":32
        },
        "precision": {
            "description": "decimal precision for display",
            "type": "integer",
            "minimum":0,
            "maximum":10
        },
        "web_link": {
            "description": "url to webpage with info about token host project",
            "type": "string",
            "minLength":3,
            "maxlength":128
        },
        "contact": {
            "description": "human contact",
            "type": "object",
            "properties": {
                "name": {
                    "description": "name of person",
                    "type": "string",
                    "maxLength": 64
                },
                "email": {
                    "description": "email",
                    "type": "string",
                    "maxLength": 64
                },
                "phone": {
                    "description": "telephone/text number",
                    "type": "string",
                    "maxLength": 32
                }
            }
        }
    },
    "required": [
        "chain",
        "symbol",
        "account",
        "name",
        "logo"
    ],
   "additionalProperties": true
  }
n13 commented 2 years ago

That makes sense, thanks!

I still think the verification can be done on contract, and probably should be?

It's not JSON data that's being passed in (or is it)?

Normally, it would be a map type that's passed in, which is represented as JSON in APIs, but internally to the contract it's actually a c++ data type of map<string, dynamic> where keys are strings, and values can be strings, vectors (list/array), or maps of <string, dynamic>.

So in this case the contract could actually verify those ~14 fields there, and make sure each field is limited in size, example string of 256 length.

Contract could verify each field exists, and could ensure min and max size for each field is correct.

In another instance where we did not have validation of the strings, people were posting strings with 100s of KB in length.

It was a bug in the client software, but still, normally the database is responsible for validation, in this case the chain.

LMK what you think.

n13 commented 2 years ago

I am just looking at the contract action

      ACTION submittoken(name submitter, string chain, name contract, symbol_code symbolcode, string json);

So this would need to change to

    // defining type
    typedef std::variant<std::monostate, uint64_t, int64_t, double, name, asset, string, bool, eosio::time_point> VariantValue; 

    ACTION submittoken(name submitter, string chain, name contract, symbol_code symbolcode,  std::map<std::string, VariantValue> json);

I just see that this construct - which we're using in the DAO - is not a full map, it's a flat map, e.g. key-value pairs, and no maps allowed as values.

So it's a bigger change.