@eth-optimism/tokenlist 4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +1 -0
- package/.env.example +2 -0
- package/.eslintrc.js +188 -0
- package/.github/CODEOWNERS +1 -0
- package/.github/mergify.yml +57 -0
- package/.github/workflows/dependabot.yml +13 -0
- package/.github/workflows/generate.yml +57 -0
- package/.github/workflows/publish.yml +50 -0
- package/.github/workflows/stale.yml +19 -0
- package/.github/workflows/test.yml +43 -0
- package/.github/workflows/validate.yml +67 -0
- package/.prettierrc.js +8 -0
- package/.vscode/extensions.json +10 -0
- package/.vscode/settings.json +10 -0
- package/CNAME +1 -0
- package/Dockerfile.bot +14 -0
- package/README.md +162 -0
- package/babel.config.js +6 -0
- package/bin/cli.ts +61 -0
- package/data/0xBTC/data.json +19 -0
- package/data/0xBTC/logo.png +0 -0
- package/data/AAVE/data.json +19 -0
- package/data/AAVE/logo.svg +1 -0
- package/data/ACX/data.json +15 -0
- package/data/ACX/logo.png +0 -0
- package/data/AELIN/data.json +11 -0
- package/data/AELIN/logo.png +0 -0
- package/data/BAL/data.json +19 -0
- package/data/BAL/logo.png +0 -0
- package/data/BANK/data.json +15 -0
- package/data/BANK/logo.png +0 -0
- package/data/BAXA/data.json +22 -0
- package/data/BAXA/logo.svg +3 -0
- package/data/BOB/data.json +16 -0
- package/data/BOB/logo.svg +11 -0
- package/data/BOND/data.json +19 -0
- package/data/BOND/logo.svg +10 -0
- package/data/BitANT/data.json +19 -0
- package/data/BitANT/logo.png +0 -0
- package/data/BitBTC/data.json +31 -0
- package/data/BitBTC/logo.png +0 -0
- package/data/CRV/data.json +13 -0
- package/data/CRV/logo.png +0 -0
- package/data/CTSI/data.json +19 -0
- package/data/CTSI/logo.svg +23 -0
- package/data/DAI/data.json +43 -0
- package/data/DAI/logo.svg +13 -0
- package/data/DCN/data.json +25 -0
- package/data/DCN/logo.svg +47 -0
- package/data/DF/data.json +20 -0
- package/data/DF/logo.svg +15 -0
- package/data/DHT/data.json +13 -0
- package/data/DHT/logo.svg +1 -0
- package/data/DOLA/data.json +19 -0
- package/data/DOLA/logo.png +0 -0
- package/data/DUCK/data.json +13 -0
- package/data/DUCK/logo.png +0 -0
- package/data/ENS/data.json +13 -0
- package/data/ENS/logo.png +0 -0
- package/data/EQZ/data.json +19 -0
- package/data/EQZ/logo.png +0 -0
- package/data/EST/data.json +13 -0
- package/data/EST/logo.png +0 -0
- package/data/ETH/data.json +25 -0
- package/data/ETH/logo.svg +13 -0
- package/data/EURT/data.json +13 -0
- package/data/EURT/logo.png +0 -0
- package/data/FLASH/data.json +16 -0
- package/data/FLASH/logo.svg +22 -0
- package/data/GTC/data.json +19 -0
- package/data/GTC/logo.svg +5 -0
- package/data/GYSR/data.json +19 -0
- package/data/GYSR/logo.png +0 -0
- package/data/HAN/data.json +22 -0
- package/data/HAN/logo.svg +25 -0
- package/data/IBEX/data.json +16 -0
- package/data/IBEX/logo.png +0 -0
- package/data/INSURE/data.json +16 -0
- package/data/INSURE/logo.png +0 -0
- package/data/KNC/data.json +19 -0
- package/data/KNC/logo.png +0 -0
- package/data/KROM/data.json +19 -0
- package/data/KROM/logo.png +0 -0
- package/data/LAND/data.json +13 -0
- package/data/LAND/logo.png +0 -0
- package/data/LDO/data.json +30 -0
- package/data/LDO/logo.svg +5 -0
- package/data/LINK/data.json +25 -0
- package/data/LINK/logo.png +0 -0
- package/data/LIZ/data.json +19 -0
- package/data/LIZ/logo.png +0 -0
- package/data/LPF/data.json +15 -0
- package/data/LPF/logo.svg +18 -0
- package/data/LRC/data.json +13 -0
- package/data/LRC/logo.png +0 -0
- package/data/LUSD/data.json +13 -0
- package/data/LUSD/logo.svg +1 -0
- package/data/LYRA/data.json +13 -0
- package/data/LYRA/logo.png +0 -0
- package/data/MASK/data.json +13 -0
- package/data/MASK/logo.svg +4 -0
- package/data/MKR/data.json +14 -0
- package/data/MKR/logo.png +0 -0
- package/data/MOCHI/data.json +16 -0
- package/data/MOCHI/logo.svg +36 -0
- package/data/MOM/data.json +19 -0
- package/data/MOM/logo.svg +5 -0
- package/data/OP/data.json +14 -0
- package/data/OP/logo.png +0 -0
- package/data/OUTb/data.json +13 -0
- package/data/OUTb/logo.svg +4 -0
- package/data/PAPER/data.json +13 -0
- package/data/PAPER/logo.svg +4 -0
- package/data/PERP/data.json +25 -0
- package/data/PERP/logo.png +0 -0
- package/data/PHTK/data.json +16 -0
- package/data/PHTK/logo.svg +14 -0
- package/data/POOL/data.json +13 -0
- package/data/POOL/logo.svg +22 -0
- package/data/POP/data.json +16 -0
- package/data/POP/logo.svg +8 -0
- package/data/PREMIA/data.json +13 -0
- package/data/PREMIA/logo.svg +4 -0
- package/data/RAI/data.json +19 -0
- package/data/RAI/logo.svg +273 -0
- package/data/RFWSTETH/data.json +21 -0
- package/data/RFWSTETH/logo.svg +36 -0
- package/data/RGT/data.json +13 -0
- package/data/RGT/logo.png +0 -0
- package/data/SARCO/data.json +13 -0
- package/data/SARCO/logo.png +0 -0
- package/data/SDL/data.json +22 -0
- package/data/SDL/logo.svg +5 -0
- package/data/SNX/data.json +43 -0
- package/data/SNX/logo.svg +20 -0
- package/data/SPANK/data.json +19 -0
- package/data/SPANK/logo.png +0 -0
- package/data/SUKU/data.json +22 -0
- package/data/SUKU/logo.png +0 -0
- package/data/THALES/data.json +13 -0
- package/data/THALES/logo.png +0 -0
- package/data/TRB/data.json +22 -0
- package/data/TRB/logo.png +0 -0
- package/data/TUSD/data.json +19 -0
- package/data/TUSD/logo.png +0 -0
- package/data/TheDAO/data.json +32 -0
- package/data/TheDAO/logo.svg +1 -0
- package/data/UBI/data.json +22 -0
- package/data/UBI/logo.svg +5 -0
- package/data/UMA/data.json +13 -0
- package/data/UMA/logo.png +0 -0
- package/data/UNI/data.json +19 -0
- package/data/UNI/logo.png +0 -0
- package/data/USDC/data.json +28 -0
- package/data/USDC/logo.png +0 -0
- package/data/USDD/data.json +19 -0
- package/data/USDD/logo.png +0 -0
- package/data/USDT/data.json +28 -0
- package/data/USDT/logo.png +0 -0
- package/data/USDplus/data.json +14 -0
- package/data/USDplus/logo.svg +9 -0
- package/data/UST/data.json +13 -0
- package/data/UST/logo.png +0 -0
- package/data/USX/data.json +31 -0
- package/data/USX/logo.svg +14 -0
- package/data/VALX/data.json +15 -0
- package/data/VALX/logo.png +0 -0
- package/data/VELO/data.json +10 -0
- package/data/VELO/logo.svg +71 -0
- package/data/WAD/data.json +19 -0
- package/data/WAD/logo.png +0 -0
- package/data/WBTC/data.json +30 -0
- package/data/WBTC/logo.svg +20 -0
- package/data/WETH/data.json +11 -0
- package/data/WETH/logo.png +0 -0
- package/data/WMP/data.json +15 -0
- package/data/WMP/logo.svg +52 -0
- package/data/WOO/data.json +16 -0
- package/data/WOO/logo.svg +1489 -0
- package/data/XCHF/data.json +13 -0
- package/data/XCHF/logo.png +0 -0
- package/data/ZRX/data.json +13 -0
- package/data/ZRX/logo.png +0 -0
- package/data/aCRV/data.json +22 -0
- package/data/aCRV/logo.svg +9 -0
- package/data/alETH/data.json +16 -0
- package/data/alETH/logo.svg +17 -0
- package/data/rETH/data.json +13 -0
- package/data/rETH/logo.png +0 -0
- package/data/sBTC/data.json +11 -0
- package/data/sBTC/logo.svg +18 -0
- package/data/sETH/data.json +11 -0
- package/data/sETH/logo.svg +23 -0
- package/data/sLINK/data.json +11 -0
- package/data/sLINK/logo.svg +23 -0
- package/data/sUSD/data.json +17 -0
- package/data/sUSD/logo.svg +17 -0
- package/data/veKWENTA/data.json +22 -0
- package/data/veKWENTA/logo.svg +24 -0
- package/data/wstETH/data.json +31 -0
- package/data/wstETH/logo.svg +11 -0
- package/dist/declarations/src/index.d.ts +79 -0
- package/dist/eth-optimism-tokenlist.cjs.d.ts +1 -0
- package/dist/eth-optimism-tokenlist.cjs.dev.js +3098 -0
- package/dist/eth-optimism-tokenlist.cjs.js +7 -0
- package/dist/eth-optimism-tokenlist.cjs.prod.js +3098 -0
- package/dist/eth-optimism-tokenlist.esm.js +3090 -0
- package/jest.config.js +5 -0
- package/optimism.defaulttokens.json +26 -0
- package/optimism.svg +4 -0
- package/optimism.tokenlist.json +3086 -0
- package/package.json +80 -0
- package/src/abi.ts +77 -0
- package/src/bot.ts +236 -0
- package/src/chains.ts +58 -0
- package/src/generate.ts +69 -0
- package/src/index.ts +71 -0
- package/src/schemas.ts +174 -0
- package/src/types.ts +33 -0
- package/src/validate.ts +271 -0
- package/tests/__snapshots__/generate.test.ts.snap +87 -0
- package/tests/data/ETH/data.json +21 -0
- package/tests/data/ETH/logo.svg +13 -0
- package/tests/data/OP/data.json +16 -0
- package/tests/data/OP/logo.png +0 -0
- package/tests/defaultTokens.test.ts +12 -0
- package/tests/generate.test.ts +20 -0
- package/tsconfig.json +27 -0
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@eth-optimism/tokenlist",
|
|
3
|
+
"description": "[Optimism] token list",
|
|
4
|
+
"version": "4.3.1",
|
|
5
|
+
"main": "dist/eth-optimism-tokenlist.cjs.js",
|
|
6
|
+
"module": "dist/eth-optimism-tokenlist.esm.js",
|
|
7
|
+
"homepage": "https://github.com/ethereum-optimism/tokenlist#readme",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"author": "roninjin10",
|
|
10
|
+
"preconstruct": {
|
|
11
|
+
"entrypoints": [
|
|
12
|
+
"index.ts"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/ethereum-optimism/tokenlist.git"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"validate": "ts-node ./bin/cli.ts validate",
|
|
21
|
+
"generate": "ts-node ./bin/cli.ts generate",
|
|
22
|
+
"generate:ci": "yarn generate --datadir ./data --outfile optimism.tokenlist.json",
|
|
23
|
+
"build": "preconstruct build",
|
|
24
|
+
"build:ci": "yarn generate:ci && yarn build",
|
|
25
|
+
"release": "yarn build:ci && npm publish",
|
|
26
|
+
"test": "jest --detectOpenHandles",
|
|
27
|
+
"lint:check": "eslint . --max-warnings=0",
|
|
28
|
+
"lint:fix": "eslint --fix .",
|
|
29
|
+
"lint": "yarn lint:fix && yarn lint:check",
|
|
30
|
+
"postinstall": "preconstruct dev",
|
|
31
|
+
"start-bot": "ts-node ./src/bot.ts"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@actions/core": "^1.4.0",
|
|
35
|
+
"@babel/eslint-parser": "^7.18.2",
|
|
36
|
+
"@eth-optimism/common-ts": "^0.6.5",
|
|
37
|
+
"@eth-optimism/contracts": "^0.5.7",
|
|
38
|
+
"@eth-optimism/core-utils": "^0.9.3",
|
|
39
|
+
"@preconstruct/cli": "^2.2.2",
|
|
40
|
+
"@types/glob": "^8.0.0",
|
|
41
|
+
"@types/jest": "^29.0.3",
|
|
42
|
+
"@types/node": "^12.0.0",
|
|
43
|
+
"@types/uuid": "^8.3.4",
|
|
44
|
+
"@typescript-eslint/eslint-plugin": "^5.26.0",
|
|
45
|
+
"@typescript-eslint/parser": "^4.26.0",
|
|
46
|
+
"@uniswap/token-lists": "^1.0.0-beta.30",
|
|
47
|
+
"ajv": "^8.11.2",
|
|
48
|
+
"ajv-formats": "^2.1.1",
|
|
49
|
+
"commander": "^9.4.0",
|
|
50
|
+
"eslint": "^8.16.0",
|
|
51
|
+
"eslint-config-prettier": "^8.3.0",
|
|
52
|
+
"eslint-config-standard": "^16.0.3",
|
|
53
|
+
"eslint-plugin-import": "^2.26.0",
|
|
54
|
+
"eslint-plugin-jsdoc": "^35.1.2",
|
|
55
|
+
"eslint-plugin-node": "^11.1.0",
|
|
56
|
+
"eslint-plugin-prefer-arrow": "^1.2.3",
|
|
57
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
58
|
+
"eslint-plugin-promise": "^5.1.0",
|
|
59
|
+
"eslint-plugin-react": "^7.24.0",
|
|
60
|
+
"eslint-plugin-unicorn": "^42.0.0",
|
|
61
|
+
"ethers": "^5.4.1",
|
|
62
|
+
"extract-zip": "^2.0.1",
|
|
63
|
+
"glob": "^8.0.3",
|
|
64
|
+
"jest": "^28.1.3",
|
|
65
|
+
"jsonschema": "^1.4.1",
|
|
66
|
+
"mocha": "^8.4.0",
|
|
67
|
+
"node-fetch": "^2.6.7",
|
|
68
|
+
"octokit": "^2.0.7",
|
|
69
|
+
"prettier": "^2.3.1",
|
|
70
|
+
"ts-jest": "^29.0.1",
|
|
71
|
+
"ts-mocha": "^10.0.0",
|
|
72
|
+
"ts-node": "^10.8.2",
|
|
73
|
+
"typescript": "^4.6.2",
|
|
74
|
+
"uuid": "^9.0.0"
|
|
75
|
+
},
|
|
76
|
+
"dependencies": {
|
|
77
|
+
"@babel/preset-typescript": "^7.18.6",
|
|
78
|
+
"babel": "^6.23.0"
|
|
79
|
+
}
|
|
80
|
+
}
|
package/src/abi.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export const FACTORY_ABI = [
|
|
2
|
+
{
|
|
3
|
+
anonymous: false,
|
|
4
|
+
inputs: [
|
|
5
|
+
{
|
|
6
|
+
indexed: true,
|
|
7
|
+
internalType: 'address',
|
|
8
|
+
name: '_l1Token',
|
|
9
|
+
type: 'address',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
indexed: true,
|
|
13
|
+
internalType: 'address',
|
|
14
|
+
name: '_l2Token',
|
|
15
|
+
type: 'address',
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
name: 'StandardL2TokenCreated',
|
|
19
|
+
type: 'event',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
inputs: [
|
|
23
|
+
{ internalType: 'address', name: '_l1Token', type: 'address' },
|
|
24
|
+
{ internalType: 'string', name: '_name', type: 'string' },
|
|
25
|
+
{ internalType: 'string', name: '_symbol', type: 'string' },
|
|
26
|
+
],
|
|
27
|
+
name: 'createStandardL2Token',
|
|
28
|
+
outputs: [],
|
|
29
|
+
stateMutability: 'nonpayable',
|
|
30
|
+
type: 'function',
|
|
31
|
+
},
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
export const TOKEN_ABI = [
|
|
35
|
+
{
|
|
36
|
+
constant: true,
|
|
37
|
+
inputs: [],
|
|
38
|
+
name: 'name',
|
|
39
|
+
outputs: [
|
|
40
|
+
{
|
|
41
|
+
name: '',
|
|
42
|
+
type: 'string',
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
payable: false,
|
|
46
|
+
stateMutability: 'view',
|
|
47
|
+
type: 'function',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
constant: true,
|
|
51
|
+
inputs: [],
|
|
52
|
+
name: 'decimals',
|
|
53
|
+
outputs: [
|
|
54
|
+
{
|
|
55
|
+
name: '',
|
|
56
|
+
type: 'uint8',
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
payable: false,
|
|
60
|
+
stateMutability: 'view',
|
|
61
|
+
type: 'function',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
constant: true,
|
|
65
|
+
inputs: [],
|
|
66
|
+
name: 'symbol',
|
|
67
|
+
outputs: [
|
|
68
|
+
{
|
|
69
|
+
name: '',
|
|
70
|
+
type: 'string',
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
payable: false,
|
|
74
|
+
stateMutability: 'view',
|
|
75
|
+
type: 'function',
|
|
76
|
+
},
|
|
77
|
+
]
|
package/src/bot.ts
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import crypto from 'crypto'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
BaseServiceV2,
|
|
7
|
+
ExpressRouter,
|
|
8
|
+
validators,
|
|
9
|
+
} from '@eth-optimism/common-ts'
|
|
10
|
+
import { Octokit } from 'octokit'
|
|
11
|
+
import extract from 'extract-zip'
|
|
12
|
+
import uuid from 'uuid'
|
|
13
|
+
|
|
14
|
+
import { version } from '../package.json'
|
|
15
|
+
|
|
16
|
+
type TOptions = {
|
|
17
|
+
secret: string
|
|
18
|
+
pat: string
|
|
19
|
+
tempdir: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type TMetrics = {}
|
|
23
|
+
|
|
24
|
+
type TState = {
|
|
25
|
+
gh: Octokit
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class Bot extends BaseServiceV2<TOptions, TMetrics, TState> {
|
|
29
|
+
constructor(options?: Partial<TOptions>) {
|
|
30
|
+
super({
|
|
31
|
+
name: 'token-list-bot',
|
|
32
|
+
version,
|
|
33
|
+
options,
|
|
34
|
+
optionsSpec: {
|
|
35
|
+
secret: {
|
|
36
|
+
secret: true,
|
|
37
|
+
desc: 'secret used to check webhook validity',
|
|
38
|
+
validator: validators.str,
|
|
39
|
+
},
|
|
40
|
+
pat: {
|
|
41
|
+
secret: true,
|
|
42
|
+
desc: 'personal access token for github',
|
|
43
|
+
validator: validators.str,
|
|
44
|
+
},
|
|
45
|
+
tempdir: {
|
|
46
|
+
desc: 'temporary directory for storing files',
|
|
47
|
+
validator: validators.str,
|
|
48
|
+
default: './tmp',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
metricsSpec: {
|
|
52
|
+
// ...
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async init(): Promise<void> {
|
|
58
|
+
this.state.gh = new Octokit({
|
|
59
|
+
auth: this.options.pat,
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// Create the temporary directory if it doesn't exist.
|
|
63
|
+
if (!fs.existsSync(this.options.tempdir)) {
|
|
64
|
+
fs.mkdirSync(this.options.tempdir)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async routes(router: ExpressRouter): Promise<void> {
|
|
69
|
+
router.post('/webhook', async (req: any, res: any) => {
|
|
70
|
+
const id = uuid.v4()
|
|
71
|
+
try {
|
|
72
|
+
// We'll need this later
|
|
73
|
+
const owner = 'ethereum-optimism'
|
|
74
|
+
const repo = 'ethereum-optimism.github.io'
|
|
75
|
+
|
|
76
|
+
// Compute the HMAC of the request body
|
|
77
|
+
const sig = Buffer.from(req.get('X-Hub-Signature-256') || '', 'utf8')
|
|
78
|
+
const hmac = crypto.createHmac('sha256', this.options.secret)
|
|
79
|
+
const digest = Buffer.from(
|
|
80
|
+
`sha256=${hmac.update(req.rawBody).digest('hex')}`,
|
|
81
|
+
'utf8'
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
// Check that the HMAC is valid
|
|
85
|
+
if (!crypto.timingSafeEqual(digest, sig)) {
|
|
86
|
+
return res
|
|
87
|
+
.status(200)
|
|
88
|
+
.json({ ok: false, message: 'invalid signature on workflow' })
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Make sure we're only looking at "Validate PR" workflows
|
|
92
|
+
if (req.body.workflow.name !== 'Validate PR') {
|
|
93
|
+
return res
|
|
94
|
+
.status(200)
|
|
95
|
+
.json({ ok: false, message: 'incorrect workflow' })
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const artifactQueryResponse = await this.state.gh.request(
|
|
99
|
+
'GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts',
|
|
100
|
+
{
|
|
101
|
+
owner,
|
|
102
|
+
repo,
|
|
103
|
+
run_id: req.body.workflow_run.id,
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
if (artifactQueryResponse.data.total_count !== 1) {
|
|
108
|
+
return res
|
|
109
|
+
.status(200)
|
|
110
|
+
.json({ ok: false, message: 'incorrect number of artifacts' })
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const artifact = artifactQueryResponse.data.artifacts[0]
|
|
114
|
+
if (artifact.name !== 'logs-artifact') {
|
|
115
|
+
return res
|
|
116
|
+
.status(200)
|
|
117
|
+
.json({ ok: false, message: 'incorrect artifact name' })
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const artifactDownloadResponse = await this.state.gh.request(
|
|
121
|
+
'GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format}',
|
|
122
|
+
{
|
|
123
|
+
owner,
|
|
124
|
+
repo,
|
|
125
|
+
artifact_id: artifact.id,
|
|
126
|
+
archive_format: 'zip',
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
const tempdir = path.resolve(this.options.tempdir, id)
|
|
131
|
+
if (!fs.existsSync(tempdir)) {
|
|
132
|
+
fs.mkdirSync(tempdir)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const temploc = path.resolve(tempdir, `${artifact.id}.zip`)
|
|
136
|
+
const tempout = path.resolve(tempdir, `${artifact.id}-out`)
|
|
137
|
+
|
|
138
|
+
fs.writeFileSync(
|
|
139
|
+
temploc,
|
|
140
|
+
Buffer.from(
|
|
141
|
+
new Uint8Array(artifactDownloadResponse.data as ArrayBuffer)
|
|
142
|
+
)
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
await extract(temploc, {
|
|
146
|
+
dir: path.resolve(tempout),
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
const pr = fs.readFileSync(path.resolve(tempout, 'pr.txt'), 'utf8')
|
|
150
|
+
const err = fs.readFileSync(path.resolve(tempout, 'err.txt'), 'utf8')
|
|
151
|
+
const std = fs.readFileSync(path.resolve(tempout, 'std.txt'), 'utf8')
|
|
152
|
+
|
|
153
|
+
if (err.length > 0) {
|
|
154
|
+
await this.state.gh.request(
|
|
155
|
+
'POST /repos/{owner}/{repo}/issues/{issue_number}/comments',
|
|
156
|
+
{
|
|
157
|
+
owner,
|
|
158
|
+
repo,
|
|
159
|
+
issue_number: parseInt(pr, 10),
|
|
160
|
+
body: `Got some errors while validating this PR. You will need to fix these errors before this PR can be reviewed.\n\`\`\`\n${err}\`\`\``,
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
return res
|
|
165
|
+
.status(200)
|
|
166
|
+
.json({ ok: true, message: 'ok with error comment on PR' })
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const warns = std.split('\n').filter((line) => {
|
|
170
|
+
return line.startsWith('warning')
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
if (warns.length > 0) {
|
|
174
|
+
await this.state.gh.request(
|
|
175
|
+
'POST /repos/{owner}/{repo}/issues/{issue_number}/comments',
|
|
176
|
+
{
|
|
177
|
+
owner,
|
|
178
|
+
repo,
|
|
179
|
+
issue_number: parseInt(pr, 10),
|
|
180
|
+
body: `Got some warnings while validating this PR. This is usually OK but this PR will require manual review if you are unable to resolve these warnings.\n\`\`\`\n${warns.join(
|
|
181
|
+
'\n'
|
|
182
|
+
)}\n\`\`\``,
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
await this.state.gh.request(
|
|
187
|
+
'POST /repos/{owner}/{repo}/issues/{issue_number}/labels',
|
|
188
|
+
{
|
|
189
|
+
owner,
|
|
190
|
+
repo,
|
|
191
|
+
issue_number: parseInt(pr, 10),
|
|
192
|
+
labels: ['requires-manual-review'],
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
return res
|
|
197
|
+
.status(200)
|
|
198
|
+
.json({ ok: true, message: 'ok with warning comment on PR' })
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Can safely remove requires-manual-review if we got here without warnings! Sometimes the
|
|
202
|
+
// label will be on the PR because a previous iteration of the workflow had warnings but the
|
|
203
|
+
// warnings were cleared up.
|
|
204
|
+
await this.state.gh.request(
|
|
205
|
+
'DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{name}',
|
|
206
|
+
{
|
|
207
|
+
owner,
|
|
208
|
+
repo,
|
|
209
|
+
issue_number: parseInt(pr, 10),
|
|
210
|
+
name: 'requires-manual-review',
|
|
211
|
+
}
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
return res.status(200).json({ ok: true, message: 'noice!' })
|
|
215
|
+
} catch (err) {
|
|
216
|
+
this.logger.error(err)
|
|
217
|
+
return res.status(500).json({ ok: false, message: 'unexpected error' })
|
|
218
|
+
} finally {
|
|
219
|
+
// Always clean up the tempdir.
|
|
220
|
+
const tempdir = path.resolve(this.options.tempdir, id)
|
|
221
|
+
if (fs.existsSync(tempdir)) {
|
|
222
|
+
fs.rmdirSync(tempdir, { recursive: true })
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async main(): Promise<void> {
|
|
229
|
+
// nothing to do here
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (require.main === module) {
|
|
234
|
+
const bot = new Bot()
|
|
235
|
+
bot.run()
|
|
236
|
+
}
|
package/src/chains.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ethers } from 'ethers'
|
|
2
|
+
|
|
3
|
+
export const NETWORK_DATA = {
|
|
4
|
+
ethereum: {
|
|
5
|
+
id: 1,
|
|
6
|
+
name: 'Mainnet',
|
|
7
|
+
provider: new ethers.providers.InfuraProvider('homestead'),
|
|
8
|
+
layer: 1,
|
|
9
|
+
pair: 'optimism',
|
|
10
|
+
bridge: '0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1',
|
|
11
|
+
},
|
|
12
|
+
optimism: {
|
|
13
|
+
id: 10,
|
|
14
|
+
name: 'Optimism',
|
|
15
|
+
provider: new ethers.providers.StaticJsonRpcProvider(
|
|
16
|
+
'https://mainnet.optimism.io'
|
|
17
|
+
),
|
|
18
|
+
layer: 2,
|
|
19
|
+
pair: 'ethereum',
|
|
20
|
+
bridge: '0x4200000000000000000000000000000000000010',
|
|
21
|
+
},
|
|
22
|
+
kovan: {
|
|
23
|
+
id: 42,
|
|
24
|
+
name: 'Kovan',
|
|
25
|
+
provider: new ethers.providers.InfuraProvider('kovan'),
|
|
26
|
+
layer: 1,
|
|
27
|
+
pair: 'optimism-kovan',
|
|
28
|
+
bridge: '0x22F24361D548e5FaAfb36d1437839f080363982B',
|
|
29
|
+
},
|
|
30
|
+
'optimism-kovan': {
|
|
31
|
+
id: 69,
|
|
32
|
+
name: 'Optimism Kovan',
|
|
33
|
+
provider: new ethers.providers.StaticJsonRpcProvider(
|
|
34
|
+
'https://kovan.optimism.io'
|
|
35
|
+
),
|
|
36
|
+
layer: 2,
|
|
37
|
+
pair: 'kovan',
|
|
38
|
+
bridge: '0x4200000000000000000000000000000000000010',
|
|
39
|
+
},
|
|
40
|
+
goerli: {
|
|
41
|
+
id: 5,
|
|
42
|
+
name: 'Goerli',
|
|
43
|
+
provider: new ethers.providers.InfuraProvider('goerli'),
|
|
44
|
+
layer: 1,
|
|
45
|
+
pair: 'optimism-goerli',
|
|
46
|
+
bridge: '0x636Af16bf2f682dD3109e60102b8E1A089FedAa8',
|
|
47
|
+
},
|
|
48
|
+
'optimism-goerli': {
|
|
49
|
+
id: 420,
|
|
50
|
+
name: 'Optimism Goerli',
|
|
51
|
+
provider: new ethers.providers.StaticJsonRpcProvider(
|
|
52
|
+
'https://goerli.optimism.io'
|
|
53
|
+
),
|
|
54
|
+
layer: 2,
|
|
55
|
+
pair: 'goerli',
|
|
56
|
+
bridge: '0x4200000000000000000000000000000000000010',
|
|
57
|
+
},
|
|
58
|
+
}
|
package/src/generate.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
|
|
4
|
+
import { glob } from 'glob'
|
|
5
|
+
|
|
6
|
+
import { version } from '../package.json'
|
|
7
|
+
import { NETWORK_DATA } from './chains'
|
|
8
|
+
import { TokenData } from './types'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Base URL where static assets are hosted.
|
|
12
|
+
*/
|
|
13
|
+
const BASE_URL = 'https://ethereum-optimism.github.io'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Generates a token list from the data in the data folder.
|
|
17
|
+
*
|
|
18
|
+
* @param datadir Directory containing data files.
|
|
19
|
+
*
|
|
20
|
+
* @returns Generated token list JSON object.
|
|
21
|
+
*/
|
|
22
|
+
export const generate = (datadir: string) => {
|
|
23
|
+
return fs
|
|
24
|
+
.readdirSync(datadir)
|
|
25
|
+
.sort((a, b) => {
|
|
26
|
+
return a.toLowerCase().localeCompare(b.toLowerCase())
|
|
27
|
+
})
|
|
28
|
+
.map((folder) => {
|
|
29
|
+
const data: TokenData = JSON.parse(
|
|
30
|
+
fs.readFileSync(path.join(datadir, folder, 'data.json'), 'utf8')
|
|
31
|
+
)
|
|
32
|
+
const logofiles = glob.sync(
|
|
33
|
+
`${path.join(datadir, folder)}/logo.{png,svg}`
|
|
34
|
+
)
|
|
35
|
+
const logoext = logofiles[0].endsWith('png') ? 'png' : 'svg'
|
|
36
|
+
return Object.entries(data.tokens).map(([chain, token]) => {
|
|
37
|
+
return {
|
|
38
|
+
chainId: NETWORK_DATA[chain].id,
|
|
39
|
+
address: token.address,
|
|
40
|
+
name: token.overrides?.name ?? data.name,
|
|
41
|
+
symbol: token.overrides?.symbol ?? data.symbol,
|
|
42
|
+
decimals: token.overrides?.decimals ?? data.decimals,
|
|
43
|
+
logoURI: `${BASE_URL}/data/${folder}/logo.${logoext}`,
|
|
44
|
+
extensions: {
|
|
45
|
+
optimismBridgeAddress:
|
|
46
|
+
token.overrides?.bridge ?? NETWORK_DATA[chain].bridge,
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
.reduce(
|
|
52
|
+
(list, tokens) => {
|
|
53
|
+
list.tokens = list.tokens.concat(tokens)
|
|
54
|
+
return list
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'Optimism',
|
|
58
|
+
logoURI: `${BASE_URL}/optimism.svg`,
|
|
59
|
+
keywords: ['scaling', 'layer2', 'infrastructure'],
|
|
60
|
+
timestamp: new Date().toISOString(),
|
|
61
|
+
tokens: [],
|
|
62
|
+
version: {
|
|
63
|
+
major: parseInt(version.split('.')[0], 10),
|
|
64
|
+
minor: parseInt(version.split('.')[1], 10),
|
|
65
|
+
patch: parseInt(version.split('.')[2], 10),
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import _extendedList from '../optimism.tokenlist.json'
|
|
2
|
+
import _defaultSymbols from '../optimism.defaulttokens.json'
|
|
3
|
+
|
|
4
|
+
export interface TokenList {
|
|
5
|
+
name: string
|
|
6
|
+
logoURI: string
|
|
7
|
+
tokens: TokenListItem[]
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface TokenListItem {
|
|
11
|
+
chainId: number
|
|
12
|
+
address: string
|
|
13
|
+
name: string
|
|
14
|
+
symbol: string
|
|
15
|
+
decimals: number
|
|
16
|
+
logoURI?: string
|
|
17
|
+
extensions?: {
|
|
18
|
+
optimismBridgeAddress?: string
|
|
19
|
+
ens?: string
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export enum TokenListChoice {
|
|
24
|
+
'EXTENDED' = 'EXTENDED',
|
|
25
|
+
'DEFAULT' = 'DEFAULT',
|
|
26
|
+
'DEFAULT_DEVNET' = 'DEFAULT_DEVNET',
|
|
27
|
+
'EXTENDED_DEVNET' = 'EXTENDED_DEVNET',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const extendedList = _extendedList
|
|
31
|
+
|
|
32
|
+
export interface FilterOptions {
|
|
33
|
+
chainId?: number
|
|
34
|
+
filterTerm?: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const filterTokens = (
|
|
38
|
+
list: TokenList['tokens'],
|
|
39
|
+
{ chainId, filterTerm }: FilterOptions = {}
|
|
40
|
+
) => {
|
|
41
|
+
return (
|
|
42
|
+
list
|
|
43
|
+
// filter by chainId
|
|
44
|
+
.filter((token) => !chainId || token.chainId === chainId)
|
|
45
|
+
// filter by filterTerm
|
|
46
|
+
.filter(
|
|
47
|
+
(token) =>
|
|
48
|
+
!filterTerm ||
|
|
49
|
+
token.address.toLowerCase().includes(filterTerm.toLowerCase()) ||
|
|
50
|
+
token.symbol.toLowerCase().includes(filterTerm.toLowerCase()) ||
|
|
51
|
+
token.name.toLowerCase().includes(filterTerm.toLowerCase())
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const defaultSymbols = new Set(_defaultSymbols)
|
|
57
|
+
|
|
58
|
+
export const defaultTokenList = {
|
|
59
|
+
...extendedList,
|
|
60
|
+
name: 'Default Token List',
|
|
61
|
+
tokens: extendedList.tokens.filter(({ symbol }) =>
|
|
62
|
+
defaultSymbols.has(symbol)
|
|
63
|
+
),
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const tokensByNetwork = {
|
|
67
|
+
1: filterTokens(extendedList.tokens, { chainId: 1 }),
|
|
68
|
+
5: filterTokens(extendedList.tokens, { chainId: 5 }),
|
|
69
|
+
10: filterTokens(extendedList.tokens, { chainId: 10 }),
|
|
70
|
+
420: filterTokens(extendedList.tokens, { chainId: 420 }),
|
|
71
|
+
}
|