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

Initial commit #746

Open
wants to merge 23 commits into
base: add-array-extension-support
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Release
on:
# manual trigger
workflow_dispatch:

jobs:
deploy:
name: release
runs-on:
group: npm-deploy
environment:
name: release
permissions:
id-token: write
contents: write
steps:
- name: Load secret
uses: 1password/load-secrets-action@581a835fb51b8e7ec56b71cf2ffddd7e68bb25e0
with:
# Export loaded secrets as environment variables
export-env: true
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
# You may need to change this to your vault name and secret name
# Refer to it by calling env.NPM_TOKEN
# This token is also limited by IP to ONLY work on the runner
NPM_TOKEN: op://npm-deploy/npm-runner-token/secret

- name: Checkout
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744

- name: Setup Node
uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7
with:
cache: yarn
node-version: 18

- name: Install dependencies
run: yarn install --immutable --immutable-cache

- name: Release
env:
NPM_CONFIG_USERCONFIG: /dev/null
NPM_TOKEN: ${{ env.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Optional
run: yarn g:release

22 changes: 22 additions & 0 deletions .github/workflows/semgrep.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Semgrep
on:
workflow_dispatch: {}
pull_request: {}
push:
branches:
- main
schedule:
# random HH:MM to avoid a load spike on GitHub Actions at 00:00
- cron: '35 11 * * *'
jobs:
semgrep:
name: semgrep/ci
runs-on: ubuntu-20.04
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
container:
image: returntocorp/semgrep
if: (github.actor != 'dependabot[bot]')
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
- run: semgrep ci
37 changes: 27 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,36 @@ This package does not include code for token list validation. You can easily do
for ease of use.

```typescript
import Ajv from 'ajv';
import { schema } from '@uniswap/token-lists'

const ajv = new Ajv({ allErrors: true });
const validate = ajv.compile(schema);
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
})
}
}

const response = await fetch('https://bridge.arbitrum.io/token-list-42161.json')
const listData = await response.json()
validate()
.then(console.log("Valid List."))
.catch(console.error)

const valid = validate(listData)
if (!valid) {
// oh no!
}
```

## Authoring token lists
Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"url": "https://uniswap.org"
},
"description": "📚 The Token Lists specification",
"version": "1.0.0-beta.27",
"version": "1.0.0-beta.34",
"license": "MIT",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
Expand All @@ -29,6 +29,10 @@
"lint": "tsdx lint src test",
"prepublishOnly": "yarn test && yarn build"
},
"publishConfig" : {
"access": "public",
"provenance": true
},
"peerDependencies": {},
"husky": {
"hooks": {
Expand Down
55 changes: 46 additions & 9 deletions src/tokenlist.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -231,19 +231,33 @@
"name": {
"type": "string",
"description": "The name of the token",
"minLength": 1,
"maxLength": 40,
"pattern": "^[ \\w.'+\\-%/À-ÖØ-öø-ÿ:&\\[\\]\\(\\)]+$",
"minLength": 0,
"maxLength": 60,
"anyOf": [
{
"const": ""
},
{
"pattern": "^[ \\S+]+$"
}
],
"examples": [
"USD Coin"
]
},
"symbol": {
"type": "string",
"description": "The symbol for the token; must be alphanumeric",
"pattern": "^[a-zA-Z0-9+\\-%/$.]+$",
"minLength": 1,
"description": "The symbol for the token",
"minLength": 0,
"maxLength": 20,
"anyOf": [
{
"const": ""
},
{
"pattern": "^\\S+$"
}
],
"examples": [
"USDC"
]
Expand Down Expand Up @@ -282,13 +296,12 @@
}
},
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string",
"description": "The name of the token list",
"minLength": 1,
"maxLength": 20,
"maxLength": 30,
"pattern": "^[\\w ]+$",
"examples": [
"My Token List"
Expand All @@ -311,6 +324,30 @@
"minItems": 1,
"maxItems": 10000
},
"tokenMap": {
"type": "object",
"description": "A mapping of key 'chainId_tokenAddress' to its corresponding token object",
"minProperties": 1,
"maxProperties": 10000,
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"$ref": "#/definitions/TokenInfo"
},
"examples": [
{
"4_0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984": {
"name": "Uniswap",
"address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984",
"symbol": "UNI",
"decimals": 18,
"chainId": 4,
"logoURI": "ipfs://QmXttGpZrECX5qCyXbBQiqgQNytVGeZW5Anewvh2jc4psg"
}
}
]
},
"keywords": {
"type": "array",
"description": "Keywords associated with the contents of the list; may be used in list discoverability",
Expand Down Expand Up @@ -363,4 +400,4 @@
"version",
"tokens"
]
}
}
15 changes: 14 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
type ExtensionValue = string | number | boolean | null | undefined;

export interface TokenInfo {
readonly chainId: number;
readonly address: string;
Expand All @@ -7,7 +9,15 @@ export interface TokenInfo {
readonly logoURI?: string;
readonly tags?: string[];
readonly extensions?: {
readonly [key: string]: string | number | boolean | null;
readonly [key: string]:
| {
[key: string]:
| {
[key: string]: ExtensionValue;
}
| ExtensionValue;
}
| ExtensionValue;
};
}

Expand All @@ -29,6 +39,9 @@ export interface TokenList {
readonly timestamp: string;
readonly version: Version;
readonly tokens: TokenInfo[];
readonly tokenMap?: {
readonly [key: string]: TokenInfo;
};
readonly keywords?: string[];
readonly tags?: Tags;
readonly logoURI?: string;
Expand Down
8 changes: 6 additions & 2 deletions test/__snapshots__/tokenlist.schema.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`schema allows additional top-level fields 1`] = `null`;

exports[`schema allows up to 10k tokens 1`] = `null`;

exports[`schema checks extensions 1`] = `null`;
Expand Down Expand Up @@ -437,9 +439,9 @@ Array [
Object {
"instancePath": "/tokens/0/name",
"keyword": "maxLength",
"message": "must NOT have more than 40 characters",
"message": "must NOT have more than 60 characters",
"params": Object {
"limit": 40,
"limit": 60,
},
"schemaPath": "#/properties/name/maxLength",
},
Expand Down Expand Up @@ -579,6 +581,8 @@ exports[`schema token symbols may contain periods 1`] = `null`;

exports[`schema works for big example schema 1`] = `null`;

exports[`schema works for empty names and symbols 1`] = `null`;

exports[`schema works for example schema 1`] = `null`;

exports[`schema works for special characters schema 1`] = `null`;
2 changes: 1 addition & 1 deletion test/schema/bigwords.tokenlist.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"timestamp": "2018-11-13T20:20:39+00:00",
"tokens": [
{
"name": "blah blah blah blah blah blah blah blah blah",
"name": "blah blah blah blah blah blah blah blah blah blah blah blah b",
"address": "0x0000000000000000000000000000000000000000",
"chainId": 1,
"decimals": 18,
Expand Down
25 changes: 25 additions & 0 deletions test/schema/empty-name-symbol.tokenlist.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "My Token List",
"timestamp": "2020-06-12T00:00:00+00:00",
"tokens": [
{
"chainId": 137,
"address": "0xc31C535F4d9A789df0c16D461B4F811543b72FEb",
"decimals": 0,
"name": "",
"symbol": ""
},
{
"chainId": 137,
"address": "0xF336f5624D34c3Be82eF3EFc4978bd2397B1524A",
"decimals": 0,
"name": "",
"symbol": ""
}
],
"version": {
"major": 1,
"minor": 0,
"patch": 0
}
}
14 changes: 14 additions & 0 deletions test/schema/example-name-symbol-special-characters.tokenlist.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@
"decimals": 18,
"name": "[brackets]&(parenthesis)",
"symbol": "symbol"
},
{
"chainId": 1,
"address": "0x76ee13b775331eeae2bc5e3b67f4a44101b27a94",
"decimals": 18,
"name": "Amatsukami",
"symbol": "天津神"
},
{
"chainId": 137,
"address": "0x841120E51aD43EfE489244728532854A352073aD",
"decimals": 6,
"name": "Timeless ERC4626-Wrapped",
"symbol": "∞-waUSDC-xPYT"
}
],
"version": {
Expand Down
24 changes: 24 additions & 0 deletions test/schema/example.tokenlist.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,30 @@
]
}
],
"tokenMap": {
"1_0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": {
"chainId": 1,
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"symbol": "USDC",
"name": "USD Coin",
"decimals": 6,
"logoURI": "ipfs://QmXfzKRvjZz3u5JRgC4v5mGVbm9ahrUiB4DgzHBsnWbTMM",
"tags": [
"stablecoin"
]
},
"1_0x39AA39c021dfbaE8faC545936693aC917d5E7563": {
"chainId": 1,
"address": "0x39AA39c021dfbaE8faC545936693aC917d5E7563",
"symbol": "cUSDC",
"name": "Compound USD Coin",
"decimals": 8,
"logoURI": "ipfs://QmUSNbwUxUYNMvMksKypkgWs8unSm8dX2GjCPBVGZ7GGMr",
"tags": [
"compound"
]
}
},
"version": {
"major": 1,
"minor": 0,
Expand Down
Loading