From 1abd84776a71d485913a950b47486ba8ab7b56bc Mon Sep 17 00:00:00 2001 From: Gabriel Montes Date: Mon, 27 Jan 2025 15:05:41 -0500 Subject: [PATCH 01/10] Improve version sync --- .husky/pre-commit | 6 ++++-- package.json | 3 +-- scripts/sync-version.js | 25 +++++++++++++++++++------ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 3a89582..7ca736d 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,2 +1,4 @@ -npm run version -lint-staged \ No newline at end of file +#! /bin/sh + +[ -n "$(node scripts/sync-version.js)" ] && git add src/hemi.tokenlist.json +lint-staged diff --git a/package.json b/package.json index 08af94c..fbf41fb 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,7 @@ "prepare": "husky", "schema:validate": "node scripts/validate-list.js", "pretest": "npm run schema:validate", - "test": "node --test", - "version": "node scripts/sync-version.js && git add ." + "test": "node --test" }, "devDependencies": { "@commitlint/cli": "19.5.0", diff --git a/scripts/sync-version.js b/scripts/sync-version.js index e46a0e2..7b2dd39 100644 --- a/scripts/sync-version.js +++ b/scripts/sync-version.js @@ -5,11 +5,24 @@ import fs from "node:fs"; const packageJson = JSON.parse(fs.readFileSync("./package.json")); const tokenList = JSON.parse(fs.readFileSync("./src/hemi.tokenlist.json")); -const [major, minor, patch] = packageJson.version.split("."); -tokenList.version.major = parseInt(major); -tokenList.version.minor = parseInt(minor); -tokenList.version.patch = parseInt(patch); +const currentVersion = [ + tokenList.version.major, + tokenList.version.minor, + tokenList.version.patch, +].join("."); -tokenList.timestamp = new Date().toISOString(); +if (currentVersion !== packageJson.version) { + const [major, minor, patch] = packageJson.version.split("."); + tokenList.version.major = parseInt(major); + tokenList.version.minor = parseInt(minor); + tokenList.version.patch = parseInt(patch); -fs.writeFileSync("src/hemi.tokenlist.json", JSON.stringify(tokenList, null, 2)); + tokenList.timestamp = new Date().toISOString(); + + fs.writeFileSync( + "src/hemi.tokenlist.json", + JSON.stringify(tokenList, null, 2), + ); + + console.log("Version updated"); +} From 360289711f737ff04eb834f750d66079bc4ad543 Mon Sep 17 00:00:00 2001 From: Gabriel Montes Date: Mon, 27 Jan 2025 15:05:06 -0500 Subject: [PATCH 02/10] Fix linter warn on Node version --- package-lock.json | 3 +++ package.json | 3 +++ 2 files changed, 6 insertions(+) diff --git a/package-lock.json b/package-lock.json index 40a0cdf..4e35f8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,9 @@ "lint-staged": "15.2.10", "prettier": "3.3.3", "viem": "^2.21.51" + }, + "engines": { + "node": ">=20" } }, "node_modules/@adraffy/ens-normalize": { diff --git a/package.json b/package.json index fbf41fb..aab2cb0 100644 --- a/package.json +++ b/package.json @@ -40,5 +40,8 @@ "prettier": "3.3.3", "viem": "^2.21.51" }, + "engines": { + "node": ">=20" + }, "type": "module" } From d18523112c0cc7db09e30b033e7935d9d68b9a49 Mon Sep 17 00:00:00 2001 From: Gabriel Montes Date: Mon, 27 Jan 2025 15:07:01 -0500 Subject: [PATCH 03/10] Remove linter warning on importing JSON files --- scripts/add-token.js | 6 +++--- scripts/sync-version.js | 8 ++++---- scripts/validate-list.js | 6 +++--- test/hemi.tokenlist.test.js | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/scripts/add-token.js b/scripts/add-token.js index b64684d..45d21ff 100644 --- a/scripts/add-token.js +++ b/scripts/add-token.js @@ -9,9 +9,9 @@ import { import { hemi, hemiSepolia } from "hemi-viem"; import fs from "node:fs"; -// eslint fails to parse "with { type: "json" }" -// See https://github.com/eslint/eslint/discussions/15305 -const tokenList = JSON.parse(fs.readFileSync("./src/hemi.tokenlist.json")); +const tokenList = JSON.parse( + fs.readFileSync("./src/hemi.tokenlist.json", "utf-8"), +); async function addToken() { const [chainIdStr, address] = process.argv.slice(2); diff --git a/scripts/sync-version.js b/scripts/sync-version.js index 7b2dd39..0a10bef 100644 --- a/scripts/sync-version.js +++ b/scripts/sync-version.js @@ -1,9 +1,9 @@ import fs from "node:fs"; -// eslint fails to parse "with { type: "json" }" -// See https://github.com/eslint/eslint/discussions/15305 -const packageJson = JSON.parse(fs.readFileSync("./package.json")); -const tokenList = JSON.parse(fs.readFileSync("./src/hemi.tokenlist.json")); +const packageJson = JSON.parse(fs.readFileSync("./package.json", "utf-8")); +const tokenList = JSON.parse( + fs.readFileSync("./src/hemi.tokenlist.json", "utf-8"), +); const currentVersion = [ tokenList.version.major, diff --git a/scripts/validate-list.js b/scripts/validate-list.js index 4cf8be9..e243bb6 100644 --- a/scripts/validate-list.js +++ b/scripts/validate-list.js @@ -3,9 +3,9 @@ import addFormats from "ajv-formats"; import fs from "node:fs"; import { exit } from "node:process"; -// eslint fails to parse "with { type: "json" }" -// See https://github.com/eslint/eslint/discussions/15305 -const tokenList = JSON.parse(fs.readFileSync("./src/hemi.tokenlist.json")); +const tokenList = JSON.parse( + fs.readFileSync("./src/hemi.tokenlist.json", "utf-8"), +); const schemaUrl = "https://raw.githubusercontent.com/Uniswap/token-lists/main/src/tokenlist.schema.json"; diff --git a/test/hemi.tokenlist.test.js b/test/hemi.tokenlist.test.js index 03006b8..e5628d7 100644 --- a/test/hemi.tokenlist.test.js +++ b/test/hemi.tokenlist.test.js @@ -5,10 +5,10 @@ import { hemi, hemiSepolia } from "hemi-viem"; import assert from "node:assert/strict"; import fs from "node:fs"; -// eslint fails to parse "with { type: "json" }" -// See https://github.com/eslint/eslint/discussions/15305 -const packageJson = JSON.parse(fs.readFileSync("./package.json")); -const tokenList = JSON.parse(fs.readFileSync("./src/hemi.tokenlist.json")); +const packageJson = JSON.parse(fs.readFileSync("./package.json", "utf-8")); +const tokenList = JSON.parse( + fs.readFileSync("./src/hemi.tokenlist.json", "utf-8"), +); const clients = Object.fromEntries( [hemi, hemiSepolia].map((chain) => [ From 7c155d0e3dc42e09e54a5333b47f0fa5e88107bb Mon Sep 17 00:00:00 2001 From: Gabriel Montes Date: Mon, 27 Jan 2025 15:08:42 -0500 Subject: [PATCH 04/10] Improve add-token params validation --- scripts/add-token.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/scripts/add-token.js b/scripts/add-token.js index 45d21ff..3fe291c 100644 --- a/scripts/add-token.js +++ b/scripts/add-token.js @@ -3,7 +3,6 @@ import { erc20Abi, getAddress as toChecksum, http, - isAddress, isAddressEqual, } from "viem"; import { hemi, hemiSepolia } from "hemi-viem"; @@ -14,25 +13,24 @@ const tokenList = JSON.parse( ); async function addToken() { - const [chainIdStr, address] = process.argv.slice(2); + const [chainIdStr, addressGiven] = process.argv.slice(2); const chainId = Number.parseInt(chainIdStr); + const address = toChecksum(addressGiven); - if (!isAddress(address)) { - throw new Error("Invalid address"); - } - - if ( - tokenList.tokens.find( - (token) => - isAddressEqual(token.address, address) && token.chainId === chainId, - ) - ) { + const found = tokenList.tokens.find( + (t) => isAddressEqual(t.address, address) && t.chainId === chainId, + ); + if (found) { console.log("Token already present"); return; } try { const chain = [hemi, hemiSepolia].find((c) => c.id === chainId); + if (!chain) { + throw new Error("Unsupported chain"); + } + const client = createPublicClient({ chain, transport: http(), @@ -55,7 +53,7 @@ async function addToken() { const repoUrl = "https://raw.githubusercontent.com/hemilabs/token-list"; const logoURI = `${repoUrl}/master/src/logos/${filename}.svg`; tokenList.tokens.push({ - address: toChecksum(address), + address, chainId, decimals, logoURI, From 902efb449466713ffe8e33bd7f2bf95750d2758b Mon Sep 17 00:00:00 2001 From: Gabriel Montes Date: Mon, 27 Jan 2025 15:12:08 -0500 Subject: [PATCH 05/10] Get remote token address on add-token --- scripts/add-token.js | 35 +++++++++++++++++++++++++++++++++++ src/hemi.tokenlist.json | 16 +--------------- test/hemi.tokenlist.test.js | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/scripts/add-token.js b/scripts/add-token.js index 3fe291c..3258059 100644 --- a/scripts/add-token.js +++ b/scripts/add-token.js @@ -49,6 +49,34 @@ async function addToken() { ) ); + // The remote token address should be read from the "REMOTE_TOKEN" function + // as "l1Token" and "remoteToken" are deprecated as per the comments in + // OptimismMintableERC20. + // And if there is an error getting the remote address, just ignore it. + // See: https://github.com/ethereum-optimism/optimism/blob/ca5855220fb2264aa32c882d056dd98da21ac47a/packages/contracts-bedrock/src/universal/OptimismMintableERC20.sol#L23 + const remoteTokenAddress = await client + .readContract({ + abi: [ + { + inputs: [], + name: "REMOTE_TOKEN", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + ], + address, + args: [], + functionName: "REMOTE_TOKEN", + }) + .catch(() => undefined); + const filename = symbol.toLowerCase().replace(".e", ""); const repoUrl = "https://raw.githubusercontent.com/hemilabs/token-list"; const logoURI = `${repoUrl}/master/src/logos/${filename}.svg`; @@ -56,6 +84,13 @@ async function addToken() { address, chainId, decimals, + extensions: remoteTokenAddress && { + bridgeInfo: { + [chain.sourceId]: { + tokenAddress: remoteTokenAddress, + }, + }, + }, logoURI, name, symbol, diff --git a/src/hemi.tokenlist.json b/src/hemi.tokenlist.json index 30d98c7..afd6572 100644 --- a/src/hemi.tokenlist.json +++ b/src/hemi.tokenlist.json @@ -42,7 +42,7 @@ "birthBlock": 575834, "bridgeInfo": { "11155111": { - "tokenAddress": "0xaa8e23fb1079ea71e0a56f48a2aa51851d8433d0" + "tokenAddress": "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0" } } }, @@ -316,13 +316,6 @@ "address": "0xbB0D083fb1be0A9f6157ec484b6C79E0A4e31C2e", "chainId": 43111, "decimals": 6, - "extensions": { - "bridgeInfo": { - "1": { - "tokenAddress": "0xdAC17F958D2ee523a2206206994597C13D831ec7" - } - } - }, "logoURI": "https://raw.githubusercontent.com/hemilabs/token-list/master/src/logos/usdt.svg", "name": "USDT", "symbol": "USDT" @@ -331,13 +324,6 @@ "address": "0xad11a8BEb98bbf61dbb1aa0F6d6F2ECD87b35afA", "chainId": 43111, "decimals": 6, - "extensions": { - "bridgeInfo": { - "1": { - "tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" - } - } - }, "logoURI": "https://raw.githubusercontent.com/hemilabs/token-list/master/src/logos/usdc.svg", "name": "Bridged USDC (Stargate)", "symbol": "USDC.e" diff --git a/test/hemi.tokenlist.test.js b/test/hemi.tokenlist.test.js index e5628d7..7851e41 100644 --- a/test/hemi.tokenlist.test.js +++ b/test/hemi.tokenlist.test.js @@ -81,6 +81,38 @@ describe("List of tokens", function () { assert.equal(logoURI, `${repoUrl}/master/src/logos/${filename}.svg`); fs.accessSync(`src/logos/${filename}.svg`); }); + + it("should have the correct remote token address", async function () { + const client = clients[chainId]; + const tokenAddress = + extensions?.bridgeInfo?.[client.chain.sourceId].tokenAddress; + if (!tokenAddress) { + this.skip(); + return; + } + + const remoteTokenAddress = await client.readContract({ + abi: [ + { + inputs: [], + name: "REMOTE_TOKEN", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + ], + address, + args: [], + functionName: "REMOTE_TOKEN", + }); + assert.equal(remoteTokenAddress, tokenAddress); + }); }); }); }); From 5e7a47475dee4caa13e2265ca8271a16ebf015e1 Mon Sep 17 00:00:00 2001 From: Gabriel Montes Date: Mon, 27 Jan 2025 15:12:53 -0500 Subject: [PATCH 06/10] Add missing birth blocks --- src/hemi.tokenlist.json | 8 ++++++++ test/hemi.tokenlist.test.js | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/hemi.tokenlist.json b/src/hemi.tokenlist.json index afd6572..a8e2a5e 100644 --- a/src/hemi.tokenlist.json +++ b/src/hemi.tokenlist.json @@ -287,6 +287,7 @@ "chainId": 43111, "decimals": 18, "extensions": { + "birthBlock": 363002, "bridgeInfo": { "1": { "tokenAddress": "0x936Ab482d6bd111910a42849D3A51Ff80BB0A711" @@ -302,6 +303,7 @@ "chainId": 43111, "decimals": 18, "extensions": { + "birthBlock": 782510, "bridgeInfo": { "1": { "tokenAddress": "0x18084fbA666a33d37592fA2633fD49a74DD93a88" @@ -316,6 +318,9 @@ "address": "0xbB0D083fb1be0A9f6157ec484b6C79E0A4e31C2e", "chainId": 43111, "decimals": 6, + "extensions": { + "birthBlock": 666946 + }, "logoURI": "https://raw.githubusercontent.com/hemilabs/token-list/master/src/logos/usdt.svg", "name": "USDT", "symbol": "USDT" @@ -324,6 +329,9 @@ "address": "0xad11a8BEb98bbf61dbb1aa0F6d6F2ECD87b35afA", "chainId": 43111, "decimals": 6, + "extensions": { + "birthBlock": 623077 + }, "logoURI": "https://raw.githubusercontent.com/hemilabs/token-list/master/src/logos/usdc.svg", "name": "Bridged USDC (Stargate)", "symbol": "USDC.e" diff --git a/test/hemi.tokenlist.test.js b/test/hemi.tokenlist.test.js index 7851e41..9da125c 100644 --- a/test/hemi.tokenlist.test.js +++ b/test/hemi.tokenlist.test.js @@ -82,6 +82,16 @@ describe("List of tokens", function () { fs.accessSync(`src/logos/${filename}.svg`); }); + it("should have a valid birth block number", function () { + const birthBlock = extensions?.birthBlock; + if (!birthBlock) { + this.skip(); + return; + } + + assert.ok(Number.isInteger(birthBlock)); + }); + it("should have the correct remote token address", async function () { const client = clients[chainId]; const tokenAddress = From 40a7b416f3ca0fc6dcc06027fec19125bb2e9c01 Mon Sep 17 00:00:00 2001 From: Gabriel Montes Date: Mon, 27 Jan 2025 15:17:25 -0500 Subject: [PATCH 07/10] Sort the token list (next time a token is added) --- scripts/add-token.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/add-token.js b/scripts/add-token.js index 3258059..fefe30c 100644 --- a/scripts/add-token.js +++ b/scripts/add-token.js @@ -96,6 +96,10 @@ async function addToken() { symbol, }); + tokenList.tokens + .sort((a, b) => a.address.toLowerCase() - b.address.toLowerCase()) + .sort((a, b) => a.chainId - b.chainId); + fs.writeFileSync( "src/hemi.tokenlist.json", JSON.stringify(tokenList, null, 2), From 37ba1300a92cc566fa8a8a295e2e0213324236d1 Mon Sep 17 00:00:00 2001 From: Gabriel Montes Date: Mon, 27 Jan 2025 15:17:44 -0500 Subject: [PATCH 08/10] Mark USDT and USDC.e as "stargate" --- src/hemi.tokenlist.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hemi.tokenlist.json b/src/hemi.tokenlist.json index a8e2a5e..4278061 100644 --- a/src/hemi.tokenlist.json +++ b/src/hemi.tokenlist.json @@ -319,7 +319,8 @@ "chainId": 43111, "decimals": 6, "extensions": { - "birthBlock": 666946 + "birthBlock": 666946, + "tunnel": "stargate" }, "logoURI": "https://raw.githubusercontent.com/hemilabs/token-list/master/src/logos/usdt.svg", "name": "USDT", @@ -330,7 +331,8 @@ "chainId": 43111, "decimals": 6, "extensions": { - "birthBlock": 623077 + "birthBlock": 623077, + "tunnel": "stargate" }, "logoURI": "https://raw.githubusercontent.com/hemilabs/token-list/master/src/logos/usdc.svg", "name": "Bridged USDC (Stargate)", From 8b3c967c1018cf159071b2e2b063fddd75b3a297 Mon Sep 17 00:00:00 2001 From: Gabriel Montes Date: Mon, 27 Jan 2025 15:22:40 -0500 Subject: [PATCH 09/10] Improve test names --- test/hemi.tokenlist.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hemi.tokenlist.test.js b/test/hemi.tokenlist.test.js index 9da125c..301eb37 100644 --- a/test/hemi.tokenlist.test.js +++ b/test/hemi.tokenlist.test.js @@ -49,7 +49,7 @@ describe("List of tokens", function () { symbol, } = token; - describe(`Token ${chainId}:${symbol}`, function () { + describe(`Token ${chainId}:${address} (${symbol})`, function () { it("should have all its addresses in the checksum format", function () { // viem's isAddress checks for checksum format assert.ok(isAddress(address)); From 47e6b9fbb652f1da2e9d027cc40786eced93745f Mon Sep 17 00:00:00 2001 From: Gabriel Montes Date: Mon, 27 Jan 2025 15:27:42 -0500 Subject: [PATCH 10/10] 1.7.0 --- package-lock.json | 4 ++-- package.json | 2 +- src/hemi.tokenlist.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4e35f8a..750e3f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@hemilabs/token-list", - "version": "1.6.0", + "version": "1.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@hemilabs/token-list", - "version": "1.6.0", + "version": "1.7.0", "license": "MIT", "devDependencies": { "@commitlint/cli": "19.5.0", diff --git a/package.json b/package.json index aab2cb0..349c129 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hemilabs/token-list", - "version": "1.6.0", + "version": "1.7.0", "description": "List of ERC-20 tokens in the Hemi Network chains", "bugs": { "url": "https://github.com/hemilabs/token-list/issues" diff --git a/src/hemi.tokenlist.json b/src/hemi.tokenlist.json index 4278061..71aeeba 100644 --- a/src/hemi.tokenlist.json +++ b/src/hemi.tokenlist.json @@ -1,9 +1,9 @@ { "name": "Hemi Token List", - "timestamp": "2025-01-27T18:08:23.402Z", + "timestamp": "2025-01-27T20:27:42.430Z", "version": { "major": 1, - "minor": 6, + "minor": 7, "patch": 0 }, "tokens": [