Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
20 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
2 changes: 2 additions & 0 deletions .github/ISSUE_TEMPLATE/1-addTokenForm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ body:
- GNOSIS_CHAIN
- ARBITRUM_ONE
- BASE
- POLYGON
- AVALANCHE
validations:
required: true
- type: input
Expand Down
2 changes: 2 additions & 0 deletions .github/ISSUE_TEMPLATE/2-addImageForm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ body:
- GNOSIS_CHAIN
- ARBITRUM_ONE
- BASE
- POLYGON
- AVALANCHE
validations:
required: true
- type: input
Expand Down
2 changes: 2 additions & 0 deletions .github/ISSUE_TEMPLATE/3-removeTokenForm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ body:
- GNOSIS_CHAIN
- ARBITRUM_ONE
- BASE
- POLYGON
- AVALANCHE
validations:
required: true
- type: input
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/updatePermitInfo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false # continue parallel jobs even if individual parts fail
matrix:
chainId: [1, 100, 8453, 42161] # all supported chains
chainId: [1, 100, 8453, 42161, 137, 43114] # all supported chains

steps:
- name: Checkout code
Expand Down
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
node_modules
build

# MacOS
.DS_Store

# Intellij
.idea

# Vscode
.vscode

# yalc
.yalc
yalc.lock
src/cowFi/TEMP*

# Temporary files
src/cowFi/TEMP*

# logs
*.log
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ Instructions for setting up and running the various scripts locally

### Setup

### Prerequisites

Currently runs on Node.js LTS/Gallium v16.20.2

```bash
# Install dependencies
yarn
Expand All @@ -60,7 +64,7 @@ yarn
yarn coingecko
```

### Download images
### Download images (deprecated)

There's a script that will fetch all images form the CowSwap list and store them in `src/public/images/<chainId>/<address>.png`

Expand Down Expand Up @@ -95,5 +99,7 @@ The script generates token list files in `src/public/` for the following network

- Ethereum (CoinGecko.1.json)
- Arbitrum (CoinGecko.42161.json, Uniswap.42161.json)
- Avalanche (Coingecko.43114.json, Uniswap.43114.json)
- Base (CoinGecko.8453.json, Uniswap.8453.json)
- Gnosis Chain (CoinGecko.100.json, Uniswap.100.json)
- Polygon (CoinGecko.137.json, Uniswap.137.json)
24 changes: 15 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,28 @@
"public": "copyfiles src/public/*.json build/lists -f",
"workflowHelper": "python3 src/scripts/workflow_helper.py",
"validate": "ajv -s node_modules/@uniswap/token-lists/dist/tokenlist.schema.json -d src/public/CowSwap.json -c ajv-formats --errors text",
"fetchPermitInfo": "yarn run-script src/permitInfo/fetchPermitInfo.ts",
"fetchAllPermitInfo": "yarn run-script src/permitInfo/fetchAllPermitInfo.ts",
"fetchPermitInfo": "yarn run-script src/permitInfo/fetchPermitInfoByChain.ts",
"fetchPermitInfo:mainnet": "yarn run fetchPermitInfo -- 1",
"fetchPermitInfo:arb1": "yarn run fetchPermitInfo -- 42161",
"fetchPermitInfo:base": "yarn run fetchPermitInfo -- 8453",
"fetchPermitInfo:gnosis": "yarn run fetchPermitInfo -- 100",
"fetchPermitInfo:sepolia": "yarn run fetchPermitInfo -- 11155111",
"recheckPermitInfo:mainnet": "yarn run fetchPermitInfo -- 1 '' '' true",
"recheckPermitInfo:arb1": "yarn run fetchPermitInfo -- 42161 '' '' true",
"recheckPermitInfo:base": "yarn run fetchPermitInfo -- 8453 '' '' true",
"recheckPermitInfo:gnosis": "yarn run fetchPermitInfo -- 100 '' '' true",
"recheckPermitInfo:sepolia": "yarn run fetchPermitInfo -- 11155111 '' '' true",
"fetchPermitInfo:avalanche": "yarn run fetchPermitInfo -- 43114",
"fetchPermitInfo:polygon": "yarn run fetchPermitInfo -- 137",
"recheckPermitInfo:mainnet": "yarn run fetchPermitInfo -- 1 true",
"recheckPermitInfo:arb1": "yarn run fetchPermitInfo -- 42161 true",
"recheckPermitInfo:base": "yarn run fetchPermitInfo -- 8453 true",
"recheckPermitInfo:gnosis": "yarn run fetchPermitInfo -- 100 true",
"recheckPermitInfo:sepolia": "yarn run fetchPermitInfo -- 11155111 true",
"recheckPermitInfo:avalanche": "yarn run fetchPermitInfo -- 43114 true",
"recheckPermitInfo:polygon": "yarn run fetchPermitInfo -- 137 true",
"run-script": "node --loader ts-node/esm --experimental-json-modules --experimental-specifier-resolution=node",
"test": "node --test"
},
"license": "(MIT OR Apache-2.0)",
"dependencies": {
"@cowprotocol/cow-sdk": "^5.7.0-RC.0",
"@cowprotocol/cow-sdk": "^5.11.0-RC.0",
"@cowprotocol/permit-utils": "^0.4.0",
"@uniswap/token-lists": "^1.0.0-beta.33",
"ajv": "^8.12.0",
Expand All @@ -47,7 +52,8 @@
"lodash": "^4.17.21",
"p-retry": "^6.1.0",
"p-throttle": "^5.1.0",
"ts-node": "^10.9.1"
"ts-node": "^10.9.1",
"winston": "^3.17.0"
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm curious why the choice of winston?
Or why the need for a dedicated logging lib.

Anyway, we use pino logger in other nodejs apps (watch tower, bff), but you probably have not dealt with them yet to know this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's kind of well used library, I can change it to pino logger if needed

},
"devDependencies": {
"@types/node": "^20.8.7",
Expand All @@ -56,4 +62,4 @@
"prettier": "^3.0.3",
"typescript": "^5.2.2"
}
}
}
2 changes: 2 additions & 0 deletions src/permitInfo/const.ts
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you run the permit script to fetch some permit info for the new networks?

Also, do you plan to add new scripts for them?
image

I know this will get too big and unmaintainable if we keep doing this, I'm open to suggestions to improve it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done some refactor

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export const DEFAULT_RPC_URLS: Record<SupportedChainId, string> = {
[SupportedChainId.BASE]: 'https://mainnet.base.org',
[SupportedChainId.GNOSIS_CHAIN]: 'https://rpc.gnosischain.com',
[SupportedChainId.SEPOLIA]: 'https://ethereum-sepolia.publicnode.com',
[SupportedChainId.AVALANCHE]: 'https://api.avax.network/ext/bc/C/rpc',
[SupportedChainId.POLYGON]: 'https://polygon-rpc.com',
}

export const BASE_PATH = join('..', 'public')
25 changes: 25 additions & 0 deletions src/permitInfo/fetchAllPermitInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import path from 'path'
import { argv, chdir } from 'node:process'

import { SupportedChainId } from '@cowprotocol/cow-sdk'
import { fetchPermitInfo } from './fetchPermitInfo'

async function fetchAllPermitInfo() {
const [, scriptPath] = argv

chdir(path.dirname(scriptPath))

Comment on lines +8 to +12
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider preserving the original working directory.

The script changes the working directory but doesn't restore it after execution, which could affect subsequent operations.

async function fetchAllPermitInfo() {
  const [, scriptPath] = argv
+  const originalDir = process.cwd()
  
  chdir(path.dirname(scriptPath))
+  
+  try {

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/permitInfo/fetchAllPermitInfo.ts around lines 7 to 11, the code changes
the working directory using chdir but does not restore the original directory
afterward. To fix this, save the current working directory before calling chdir,
and after the operations that require the directory change are complete, restore
the original working directory by calling chdir again with the saved path.

for (const chainId in SupportedChainId) {
if (!isNaN(Number(chainId))) {
await fetchPermitInfo({
chainId: chainId as unknown as SupportedChainId,
tokenListPath: undefined,
rpcUrl: undefined,
recheckUnsupported: false,
forceRecheck: false,
})
}
}
}

fetchAllPermitInfo()
34 changes: 10 additions & 24 deletions src/permitInfo/fetchPermitInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import {
import { JsonRpcProvider } from '@ethersproject/providers'
import { readFileSync, writeFileSync } from 'node:fs'
import * as path from 'node:path'
import { argv, chdir, env, exit } from 'node:process'
import { env, exit } from 'node:process'
import pRetry from 'p-retry'
import pThrottle from 'p-throttle'
import { BASE_PATH, SPENDER_ADDRESS } from './const'
Expand All @@ -47,25 +47,16 @@ import { getTokensFromTokenList } from './utils/getTokensFromTokenList'
import { getUnsupportedTokensFromPermitInfo } from './utils/getUnsupportedTokensFromPermitInfo'
import { sortPermitInfo } from './utils/sortPermitInfo'

// TODO: maybe make the args nicer?
// Get args from cli: chainId, optional token lists path, optional rpcUrl, optional recheckUnsupported flag
const [, scriptPath, chainId, tokenListPath, rpcUrl, recheckUnsupported, forceRecheck] = argv

if (!chainId) {
console.error('ChainId is missing. Invoke the script with the chainId as the first parameter.')
exit(1)
export type FetchPermitInfoOptions = {
chainId: SupportedChainId
tokenListPath?: string
rpcUrl?: string
recheckUnsupported?: boolean
forceRecheck?: boolean
}

// Change to script dir so relative paths work properly
chdir(path.dirname(scriptPath))

async function fetchPermitInfo(
chainId: SupportedChainId,
tokenListPath: string | undefined,
rpcUrl: string | undefined,
recheckUnsupported: boolean = false,
forceRecheck: boolean = false,
): Promise<void> {
export async function fetchPermitInfo(options: FetchPermitInfoOptions): Promise<void> {
const { chainId, tokenListPath, rpcUrl, recheckUnsupported, forceRecheck } = options
// Load existing permitInfo.json file for given chainId
const permitInfoPath = path.join(BASE_PATH, `PermitInfo.${chainId}.json`)

Expand Down Expand Up @@ -99,7 +90,7 @@ async function fetchPermitInfo(
const existingInfo = allPermitInfo[token.address.toLowerCase()]

return pRetry(
async () => _fetchPermitInfo(chainId, provider, token, existingInfo, recheckUnsupported, forceRecheck),
async () => _fetchPermitInfo(chainId, provider, token, existingInfo, !!recheckUnsupported, !!forceRecheck),
{
retries: 3,
},
Expand Down Expand Up @@ -171,8 +162,3 @@ async function _fetchPermitInfo(
}
}
}

// Execute the script
fetchPermitInfo(+chainId as SupportedChainId, tokenListPath, rpcUrl, !!recheckUnsupported, !!forceRecheck).then(() =>
console.info(`Done 🏁`),
)
28 changes: 28 additions & 0 deletions src/permitInfo/fetchPermitInfoByChain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import path from "path"
import { argv, chdir, exit } from 'node:process'

import { SupportedChainId } from '@cowprotocol/cow-sdk'
import { fetchPermitInfo } from "./fetchPermitInfo"

function fetchPermitInfoByChain() {
const [, scriptPath, chainId, forceRecheck] = argv

if (!chainId) {
console.error('ChainId is missing. Invoke the script with the chainId as the first parameter.')
exit(1)
}

// Change to script dir so relative paths work properly
chdir(path.dirname(scriptPath))

// Execute the script
fetchPermitInfo({
chainId: +chainId as SupportedChainId,
tokenListPath: undefined,
rpcUrl: undefined,
recheckUnsupported: false,
forceRecheck: forceRecheck === 'true',
}).then(() => console.info(`Done 🏁`))
}
Comment on lines +7 to +26
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling and improve input validation.

The function lacks error handling for the promise returned by fetchPermitInfo. Additionally, there's minimal validation for the chainId parameter - it only checks for presence but not for validity.

function fetchPermitInfoByChain() {
    const [, scriptPath, chainId, forceRecheck] = argv
  
    if (!chainId) {
      console.error('ChainId is missing. Invoke the script with the chainId as the first parameter.')
      exit(1)
    }
+
+    // Validate chainId is numeric
+    const parsedChainId = Number(chainId)
+    if (isNaN(parsedChainId)) {
+      console.error('ChainId must be a valid number.')
+      exit(1)
+    }
  
    // Change to script dir so relative paths work properly
    chdir(path.dirname(scriptPath))
  
    // Execute the script
    fetchPermitInfo({
-      chainId: +chainId as SupportedChainId,
+      chainId: parsedChainId as SupportedChainId,
      tokenListPath: undefined,
      rpcUrl: undefined,
      recheckUnsupported: false,
      forceRecheck: forceRecheck === 'true',
-    }).then(() => console.info(`Done 🏁`))
+    })
+      .then(() => console.info(`Done 🏁`))
+      .catch(error => {
+        console.error(`Failed to fetch permit info: ${error.message}`)
+        exit(1)
+      })
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function fetchPermitInfoByChain() {
const [, scriptPath, chainId, forceRecheck] = argv
if (!chainId) {
console.error('ChainId is missing. Invoke the script with the chainId as the first parameter.')
exit(1)
}
// Change to script dir so relative paths work properly
chdir(path.dirname(scriptPath))
// Execute the script
fetchPermitInfo({
chainId: +chainId as SupportedChainId,
tokenListPath: undefined,
rpcUrl: undefined,
recheckUnsupported: false,
forceRecheck: forceRecheck === 'true',
}).then(() => console.info(`Done 🏁`))
}
function fetchPermitInfoByChain() {
const [, scriptPath, chainId, forceRecheck] = argv
if (!chainId) {
console.error('ChainId is missing. Invoke the script with the chainId as the first parameter.')
exit(1)
}
// Validate chainId is numeric
const parsedChainId = Number(chainId)
if (isNaN(parsedChainId)) {
console.error('ChainId must be a valid number.')
exit(1)
}
// Change to script dir so relative paths work properly
chdir(path.dirname(scriptPath))
// Execute the script
fetchPermitInfo({
chainId: parsedChainId as SupportedChainId,
tokenListPath: undefined,
rpcUrl: undefined,
recheckUnsupported: false,
forceRecheck: forceRecheck === 'true',
})
.then(() => console.info(`Done 🏁`))
.catch(error => {
console.error(`Failed to fetch permit info: ${error.message}`)
exit(1)
})
}
🤖 Prompt for AI Agents
In src/permitInfo/fetchPermitInfoByChain.ts around lines 7 to 26, add error
handling for the promise returned by fetchPermitInfo by appending a catch block
to handle and log any errors. Also, improve input validation by verifying that
chainId is not only present but also a valid SupportedChainId before proceeding,
and exit with an error message if invalid.


fetchPermitInfoByChain()
2 changes: 2 additions & 0 deletions src/permitInfo/utils/getTokensFromTokenList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const tokenListsByNetwork: Record<SupportedChainId, string> = {
[SupportedChainId.BASE]: 'CowSwap.json',
[SupportedChainId.GNOSIS_CHAIN]: 'CowSwap.json',
[SupportedChainId.SEPOLIA]: 'CowSwapSepolia.json',
[SupportedChainId.POLYGON]: 'CowSwap.json',
[SupportedChainId.AVALANCHE]: 'CowSwap.json',
}

export async function getTokensFromTokenList(
Expand Down
Loading