-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: override aux list props (#768)
* refactor: extract processTokenList into a new file * feat: add option to override token details * chore: update lists * fix: avoid issue where all values use the same object
- Loading branch information
1 parent
b33f564
commit d4f53bb
Showing
9 changed files
with
5,918 additions
and
5,876 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,16 @@ | ||
import { mapSupportedNetworks, SupportedChainId } from '@cowprotocol/cow-sdk' | ||
import { fetchAndProcessCoingeckoTokens } from './coingecko' | ||
import { fetchAndProcessUniswapTokens } from './uniswap' | ||
import { getCoingeckoTokenIdsMap } from './utils' | ||
import { getCoingeckoTokenIdsMap, OverridesPerChain } from './utils' | ||
|
||
const OVERRIDES: OverridesPerChain = mapSupportedNetworks(() => ({})) | ||
OVERRIDES[SupportedChainId.BASE]['0x18dd5b087bca9920562aff7a0199b96b9230438b'] = { decimals: 8 } // incorrect decimals set on CoinGecko's list | ||
|
||
async function main(): Promise<void> { | ||
const COINGECKO_IDS_MAP = await getCoingeckoTokenIdsMap() | ||
|
||
fetchAndProcessCoingeckoTokens(COINGECKO_IDS_MAP) | ||
fetchAndProcessUniswapTokens(COINGECKO_IDS_MAP) | ||
fetchAndProcessCoingeckoTokens(COINGECKO_IDS_MAP, OVERRIDES) | ||
fetchAndProcessUniswapTokens(COINGECKO_IDS_MAP, OVERRIDES) | ||
} | ||
|
||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import { SupportedChainId } from '@cowprotocol/cow-sdk' | ||
import { TokenList } from '@uniswap/token-lists' | ||
import * as fs from 'fs' | ||
import path from 'path' | ||
import { DISPLAY_CHAIN_NAMES, Overrides, TokenInfo } from './utils' | ||
|
||
const FORMATTER = new Intl.NumberFormat('en-us', { style: 'currency', currency: 'USD' }) | ||
|
||
function getEmptyList(): Partial<TokenList> { | ||
return { | ||
keywords: ['defi'], | ||
version: { major: 0, minor: 0, patch: 0 }, | ||
tokens: [], | ||
} | ||
} | ||
|
||
function getListName(chain: SupportedChainId, prefix: string): string { | ||
return `${prefix} on ${DISPLAY_CHAIN_NAMES[chain]}` | ||
} | ||
|
||
function getOutputPath(prefix: string, chainId: SupportedChainId): string { | ||
return `src/public/${prefix}.${chainId}.json` | ||
} | ||
|
||
function getLocalTokenList(listPath: string, defaultEmptyList: Partial<TokenList>): Partial<TokenList> { | ||
try { | ||
return JSON.parse(fs.readFileSync(listPath, 'utf8')) | ||
} catch (error) { | ||
console.warn(`Error reading token list from ${listPath}:`, error) | ||
return defaultEmptyList | ||
} | ||
} | ||
|
||
function getTokenListVersion(list: Partial<TokenList>, tokens: TokenInfo[]): TokenList['version'] { | ||
const version = list.version || { major: 0, minor: 0, patch: 0 } | ||
const currentAddresses = new Set(list.tokens?.map((token) => token.address.toLowerCase()) || []) | ||
const newAddresses = new Set(tokens.map((token) => token.address.toLowerCase())) | ||
|
||
// Check for removed tokens | ||
if (newAddresses.size < currentAddresses.size || !isSubsetOf(currentAddresses, newAddresses)) { | ||
return { major: version.major + 1, minor: 0, patch: 0 } | ||
} | ||
|
||
// Check for added tokens | ||
if (newAddresses.size > currentAddresses.size) { | ||
return { ...version, minor: version.minor + 1, patch: 0 } | ||
} | ||
|
||
// Check for changes in token details | ||
if (currentAddresses.size === newAddresses.size) { | ||
for (const listToken of list.tokens || []) { | ||
const token = tokens.find((token) => token.address.toLowerCase() === listToken.address.toLowerCase()) | ||
if ( | ||
token && | ||
(listToken.name !== token.name || | ||
listToken.symbol !== token.symbol || | ||
listToken.decimals !== token.decimals || | ||
listToken.logoURI !== token.logoURI) | ||
) { | ||
return { ...version, patch: version.patch + 1 } | ||
} | ||
} | ||
} | ||
|
||
return version | ||
} | ||
|
||
interface SaveUpdatedTokensParams { | ||
chainId: SupportedChainId | ||
prefix: string | ||
logo: string | ||
tokens: TokenInfo[] | ||
listName: string | ||
} | ||
|
||
function saveUpdatedTokens({ chainId, prefix, logo, tokens, listName }: SaveUpdatedTokensParams): void { | ||
const tokenListPath = path.join(getOutputPath(prefix, chainId)) | ||
const currentList = getLocalTokenList(tokenListPath, getEmptyList()) | ||
|
||
try { | ||
const version = getTokenListVersion(currentList, tokens) | ||
|
||
if (JSON.stringify(currentList.version) !== JSON.stringify(version)) { | ||
const updatedList: TokenList = { | ||
...currentList, | ||
tokens, | ||
name: listName, | ||
logoURI: logo, | ||
version, | ||
timestamp: new Date().toISOString(), | ||
} | ||
fs.writeFileSync(tokenListPath, JSON.stringify(updatedList, null, 2)) | ||
console.log(`Token list saved to ${tokenListPath}`) | ||
} else { | ||
console.log(`No changes detected. Token list not updated.`) | ||
} | ||
} catch (error) { | ||
console.error(`Error saving token list to ${tokenListPath}:`, error) | ||
} | ||
} | ||
|
||
interface ProcessTokenListParams { | ||
chainId: SupportedChainId | ||
tokens: TokenInfo[] | ||
prefix: string | ||
logo: string | ||
overrides?: Overrides | ||
logMessage: string | ||
} | ||
|
||
export async function processTokenList({ | ||
chainId, | ||
tokens, | ||
prefix, | ||
logo, | ||
overrides = {}, | ||
logMessage, | ||
}: ProcessTokenListParams): Promise<void> { | ||
console.log(`🥇 ${logMessage} on chain ${chainId}`) | ||
|
||
tokens.forEach((token, index) => { | ||
const volumeStr = token.volume ? `: ${FORMATTER.format(token.volume)}` : '' | ||
console.log(`\t-${(index + 1).toString().padStart(3, '0')}) ${token.name} (${token.symbol})${volumeStr}`) | ||
}) | ||
|
||
const updatedTokens = tokens.map(({ volume: _, ...token }) => { | ||
const override = overrides[token.address.toLowerCase()] | ||
return { | ||
...token, | ||
...override, | ||
logoURI: token.logoURI ? token.logoURI.replace(/thumb/, 'large') : undefined, | ||
} | ||
}) | ||
|
||
const listName = getListName(chainId, prefix) | ||
saveUpdatedTokens({ chainId, prefix, logo, tokens: updatedTokens, listName }) | ||
} | ||
|
||
function isSubsetOf(setA: Set<string>, setB: Set<string>): boolean { | ||
for (let item of setA) { | ||
if (!setB.has(item)) { | ||
return false | ||
} | ||
} | ||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.