Skip to content

Commit

Permalink
Auto l1 addr (#33)
Browse files Browse the repository at this point in the history
* Improve version sync

* Fix linter warn on Node version

* Remove linter warning on importing JSON files

* Improve add-token params validation

* Get remote token address on add-token

* Add missing birth blocks

* Sort the token list (next time a token is added)

* Mark USDT and USDC.e as "stargate"

* Improve test names

* 1.7.0
  • Loading branch information
gabmontes authored Jan 27, 2025
1 parent 6c7e274 commit 5b0b075
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 54 deletions.
6 changes: 4 additions & 2 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
npm run version
lint-staged
#! /bin/sh

[ -n "$(node scripts/sync-version.js)" ] && git add src/hemi.tokenlist.json
lint-staged
7 changes: 5 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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",
Expand All @@ -41,5 +40,8 @@
"prettier": "3.3.3",
"viem": "^2.21.51"
},
"engines": {
"node": ">=20"
},
"type": "module"
}
69 changes: 53 additions & 16 deletions scripts/add-token.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,34 @@ import {
erc20Abi,
getAddress as toChecksum,
http,
isAddress,
isAddressEqual,
} from "viem";
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);
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(),
Expand All @@ -51,18 +49,57 @@ 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`;
tokenList.tokens.push({
address: toChecksum(address),
address,
chainId,
decimals,
extensions: remoteTokenAddress && {
bridgeInfo: {
[chain.sourceId]: {
tokenAddress: remoteTokenAddress,
},
},
},
logoURI,
name,
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),
Expand Down
33 changes: 23 additions & 10 deletions scripts/sync-version.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
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 [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");
}
6 changes: 3 additions & 3 deletions scripts/validate-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
22 changes: 9 additions & 13 deletions src/hemi.tokenlist.json
Original file line number Diff line number Diff line change
@@ -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": [
Expand Down Expand Up @@ -42,7 +42,7 @@
"birthBlock": 575834,
"bridgeInfo": {
"11155111": {
"tokenAddress": "0xaa8e23fb1079ea71e0a56f48a2aa51851d8433d0"
"tokenAddress": "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0"
}
}
},
Expand Down Expand Up @@ -287,6 +287,7 @@
"chainId": 43111,
"decimals": 18,
"extensions": {
"birthBlock": 363002,
"bridgeInfo": {
"1": {
"tokenAddress": "0x936Ab482d6bd111910a42849D3A51Ff80BB0A711"
Expand All @@ -302,6 +303,7 @@
"chainId": 43111,
"decimals": 18,
"extensions": {
"birthBlock": 782510,
"bridgeInfo": {
"1": {
"tokenAddress": "0x18084fbA666a33d37592fA2633fD49a74DD93a88"
Expand All @@ -317,11 +319,8 @@
"chainId": 43111,
"decimals": 6,
"extensions": {
"bridgeInfo": {
"1": {
"tokenAddress": "0xdAC17F958D2ee523a2206206994597C13D831ec7"
}
}
"birthBlock": 666946,
"tunnel": "stargate"
},
"logoURI": "https://raw.githubusercontent.com/hemilabs/token-list/master/src/logos/usdt.svg",
"name": "USDT",
Expand All @@ -332,11 +331,8 @@
"chainId": 43111,
"decimals": 6,
"extensions": {
"bridgeInfo": {
"1": {
"tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
}
}
"birthBlock": 623077,
"tunnel": "stargate"
},
"logoURI": "https://raw.githubusercontent.com/hemilabs/token-list/master/src/logos/usdc.svg",
"name": "Bridged USDC (Stargate)",
Expand Down
52 changes: 47 additions & 5 deletions test/hemi.tokenlist.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => [
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -81,6 +81,48 @@ describe("List of tokens", function () {
assert.equal(logoURI, `${repoUrl}/master/src/logos/${filename}.svg`);
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 =
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);
});
});
});
});

0 comments on commit 5b0b075

Please sign in to comment.