diff --git a/README.md b/README.md index 97f13e8a..a14d2d5e 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,16 @@ -# @uniswap/token-lists (beta) +# Zora Uniswap Token List -[![Tests](https://github.com/Uniswap/token-lists/workflows/Tests/badge.svg)](https://github.com/Uniswap/token-lists/actions?query=workflow%3ATests) -[![npm](https://img.shields.io/npm/v/@uniswap/token-lists)](https://unpkg.com/@uniswap/token-lists@latest/) +[![Tests](https://github.com/ourzora/uniswap-token-lists/workflows/Tests/badge.svg)](https://github.com/Uniswap/token-lists/actions?query=workflow%3ATests) +[![Validation](https://github.com/ourzora/uniswap-token-lists/workflows/Tests/badge.svg)](https://github.com/Uniswap/token-lists/actions?query=workflow%3ATests) This package includes a JSON schema for token lists, and TypeScript utilities for working with token lists. The JSON schema represents the technical specification for a token list which can be used in a dApp interface, such as the Uniswap Interface. +## Adding to the Zora Token List + +To add a token to the Zora Token List, create a pull request to this repo with an edited `ZORA.tokenlist.json` file. + ## What are token lists? Uniswap Token Lists is a specification for lists of token metadata (e.g. address, decimals, ...) that can be used by any dApp interfaces that needs one or more lists of tokens. @@ -24,109 +28,7 @@ The JSON schema ID is [https://uniswap.org/tokenlist.schema.json](https://uniswa ## Validating token lists -This package does not include code for token list validation. You can easily do this by including a library such as -[ajv](https://ajv.js.org/) to perform the validation against the JSON schema. The schema is exported from the package -for ease of use. - -```typescript - -import { schema } from '@uniswap/token-lists' -import Ajv from 'ajv' -import addFormats from 'ajv-formats' -import fetch from 'node-fetch' - -const ARBITRUM_LIST = 'https://bridge.arbitrum.io/token-list-42161.json' - -async function validate() { - const ajv = new Ajv({ allErrors: true, verbose: true }) - addFormats(ajv) - const validator = ajv.compile(schema); - const response = await fetch(ARBITRUM_LIST) - const data = await response.json() - const valid = validator(data) - if (valid) { - return valid - } - if (validator.errors) { - throw validator.errors.map(error => { - delete error.data - return error - }) - } -} - -validate() - .then(console.log("Valid List.")) - .catch(console.error) - +To validate the token list, run the following command ``` - -## Authoring token lists - -### Manual - -The best way to manually author token lists is to use an editor that supports JSON schema validation. Most popular -code editors do, such as [IntelliJ](https://www.jetbrains.com/help/idea/json.html#ws_json_schema_add_custom) or -[VSCode](https://code.visualstudio.com/docs/languages/json#_json-schemas-and-settings). Other editors -can be found [here](https://json-schema.org/implementations.html#editors). - -The schema is registered in the [SchemaStore](https://github.com/SchemaStore/schemastore), and any file that matches -the pattern `*.tokenlist.json` should -[automatically utilize](https://www.jetbrains.com/help/idea/json.html#ws_json_using_schemas) -the JSON schema for the [supported text editors](https://www.schemastore.org/json/#editors). - -In order for your token list to be able to be used, it must pass all JSON schema validation. - -### Automated - -If you want to automate token listing, e.g. by pulling from a smart contract, or other sources, you can use this -npm package to take advantage of the JSON schema for validation and the TypeScript types. -Otherwise, you are simply working with JSON. All the usual tools apply, e.g.: - -```typescript -import { TokenList, schema } from '@uniswap/token-lists' - -// generate your token list however you like. -const myList: TokenList = generateMyTokenList(); - -// use a tool like `ajv` to validate your generated token list -validateMyTokenList(myList, schema); - -// print the resulting JSON to stdout -process.stdout.write(JSON.stringify(myList)); +yarn validate ``` - -## Semantic versioning - -Lists include a `version` field, which follows [semantic versioning](https://semver.org/). - -List versions must follow the rules: - -- Increment major version when tokens are removed -- Increment minor version when tokens are added -- Increment patch version when tokens already on the list have minor details changed (name, symbol, logo URL, decimals) - -Changing a token address or chain ID is considered both a remove and an add, and should be a major version update. - -Note that list versioning is used to improve the user experience, but not for security, i.e. list versions are not meant -to provide protection against malicious updates to a token list; i.e. the list semver is used as a lossy compression -of the diff of list updates. List updates may still be diffed in the client dApp. - -## Deploying your list - -Once you have authored the list, you can make it available at any URI. Prefer pinning your list to IPFS -(e.g. via [pinata.cloud](https://pinata.cloud)) and referencing the list by an ENS name that resolves to the -[contenthash](https://eips.ethereum.org/EIPS/eip-1577). - -If hosted on HTTPS, make sure the endpoint is configured to send an access-control-allow-origin header to avoid CORS errors. - -### Linking an ENS name to the list - -An ENS name can be assigned to an IPFS hash via the [contenthash](https://eips.ethereum.org/EIPS/eip-1577) text record. -This is the preferred way of referencing your list. - -## Examples - -You can find a simple example of a token list in [test/schema/example.tokenlist.json](test/schema/example.tokenlist.json). - -A snapshot of the Uniswap default list encoded as a token list is found in [test/schema/bigexample.tokenlist.json](test/schema/bigexample.tokenlist.json). diff --git a/package.json b/package.json index c4ee3b50..8d36d003 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ }, "module": "dist/token-lists.esm.js", "devDependencies": { - "ajv": "^6.12.6", + "ajv": "^8.6.1", "ajv-formats": "^2.1.0", "fs": "^0.0.1-security", "husky": "^4.2.5", diff --git a/src/validate.ts b/src/validate.ts index 3f67b8f2..94dda93f 100644 --- a/src/validate.ts +++ b/src/validate.ts @@ -1,5 +1,6 @@ import fs from 'fs'; import ajv from 'ajv'; +import addFormats from 'ajv-formats'; import { TokenList } from 'types'; function run() { @@ -9,12 +10,13 @@ function run() { const schema = JSON.parse( fs.readFileSync('src/tokenlist.schema.json', 'utf-8') ); - const validate = new ajv().compile(schema); + const validator = new ajv(); + addFormats(validator); - const valid = validate(list); + const valid = validator.validate(schema, list); if (!valid) { - console.error(validate.errors); + console.error(validator.errors); process.exit(1); } else { console.log('Tokenlist is valid!'); diff --git a/yarn.lock b/yarn.lock index 459488bc..983e4a66 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1440,7 +1440,7 @@ ajv-formats@^2.1.0: dependencies: ajv "^8.0.0" -ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.6: +ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1460,6 +1460,16 @@ ajv@^8.0.0: require-from-string "^2.0.2" uri-js "^4.2.2" +ajv@^8.6.1: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ansi-colors@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"