Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 5 additions & 5 deletions .github/ISSUE_TEMPLATE/token-submission.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Token Submission
description: Submit a new token to the MegaETH Token List
title: "[Token] "
labels: ["token-submission"]
title: '[Token] '
labels: ['token-submission']
body:
- type: markdown
attributes:
Expand Down Expand Up @@ -37,14 +37,14 @@ body:
attributes:
label: Ethereum Address
description: Leave blank if not deployed on Ethereum
placeholder: "0x..."
placeholder: '0x...'

- type: input
id: megaeth-address
attributes:
label: MegaETH Address
description: Leave blank if not deployed on MegaETH
placeholder: "0x..."
placeholder: '0x...'

- type: dropdown
id: token-type
Expand All @@ -61,7 +61,7 @@ body:
attributes:
label: Bridge Address
description: Required if token is bridged
placeholder: "0x..."
placeholder: '0x...'

- type: input
id: website
Expand Down
5 changes: 5 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
## Token Submission

### Token Information

- **Token Name**:
- **Token Symbol**:
- **Decimals**:

### Chain Addresses

- [ ] Ethereum: `0x...`
- [ ] MegaETH: `0x...`

### Bridge Information (if applicable)

- [ ] This is a **native** token (no bridge)
- [ ] This is a **bridged** token
- Bridge Address: `0x...`

### Checklist

- [ ] Created folder `data/<SYMBOL>/`
- [ ] Added `data.json` with correct token information
- [ ] Added `logo.svg` or `logo.png` (256x256 recommended)
- [ ] Addresses are checksummed (EIP-55)
- [ ] Token is deployed on specified chain(s)

### Additional Information

<!-- Any additional context about the token -->
7 changes: 5 additions & 2 deletions .github/workflows/generate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ jobs:
- name: Install dependencies
run: npm install

- name: Format files
run: npm run format

- name: Generate token list
run: npm run generate

- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "bot(ci): regenerate token list"
file_pattern: "megaeth.tokenlist.json"
commit_message: 'bot(ci): regenerate token list'
file_pattern: '*.json data/**'
15 changes: 15 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,18 @@ jobs:
exit 1
fi
echo "✅ PR only modifies allowed files in data/"

format-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install dependencies
run: npm install

- name: Check formatting
run: npx prettier --check .
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ node_modules/
dist/
*.log
.DS_Store
src/__tests__/
.claude
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
dist/
package-lock.json
megaeth.tokenlist.json
*.svg
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true,
"arrowParens": "always"
}
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

The official token registry for the MegaETH ecosystem. This repository maintains a curated list of ERC-20 tokens deployed on MegaETH and their corresponding Ethereum mainnet addresses for bridging.

Built following the [Uniswap Token List](https://uniswap.org/blog/token-lists) standard.

## Supported Chains

| Chain | Chain ID | Type |
|-------|----------|------|
| Ethereum | 1 | L1 |
| MegaETH | 4326 | L2 |
| Chain | Chain ID | Type |
| -------- | -------- | ---- |
| Ethereum | 1 | L1 |
| MegaETH | 4326 | L2 |

## Adding a Token

Expand Down Expand Up @@ -42,6 +40,7 @@ Built following the [Uniswap Token List](https://uniswap.org/blog/token-lists) s
- **Bridged token**: Has `bridge` field with the bridge contract address

Example for a bridged token on MegaETH:

```json
{
"megaeth": {
Expand Down
3 changes: 3 additions & 0 deletions data/WETH/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"decimals": 18,
"description": "Wrapped Ether on MegaETH",
"tokens": {
"ethereum": {
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
},
"megaeth": {
"address": "0x4200000000000000000000000000000000000006"
}
Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/__tests__/**/*.test.ts'],
};
}
2 changes: 1 addition & 1 deletion megaeth.tokenlist.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@
"logoURI": "https://raw.githubusercontent.com/megaeth-labs/mega-tokenlist/main/data/WETH/logo.svg"
}
]
}
}
17 changes: 17 additions & 0 deletions package-lock.json

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

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"scripts": {
"generate": "ts-node src/generate.ts",
"build": "pnpm generate",
"test": "jest"
"test": "jest",
"format": "prettier --write ."
},
"keywords": [
"megaeth",
Expand All @@ -19,6 +20,7 @@
"@types/jest": "^29.5.0",
"@types/node": "^20.0.0",
"jest": "^29.7.0",
"prettier": "^3.2.0",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.2",
"typescript": "^5.3.0"
Expand Down
12 changes: 6 additions & 6 deletions src/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ export const CHAINS = {
name: 'MegaETH',
layer: 2,
},
} as const;
} as const

export type Chain = keyof typeof CHAINS;
export type L1Chain = 'ethereum';
export type L2Chain = 'megaeth';
export type Chain = keyof typeof CHAINS
export type L1Chain = 'ethereum'
export type L2Chain = 'megaeth'

// Chain ID lookup
export const CHAIN_IDS: Record<Chain, number> = {
ethereum: 1,
megaeth: 4326,
};
}

// L2 to L1 mapping (for bridge relationships)
export const L2_TO_L1: Record<L2Chain, L1Chain> = {
megaeth: 'ethereum',
};
}
79 changes: 42 additions & 37 deletions src/generate.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,51 @@
import * as fs from 'fs';
import * as path from 'path';
import { CHAIN_IDS, type Chain } from './chains';
import type { TokenData, TokenList, TokenListToken } from './types';
import * as fs from 'fs'
import * as path from 'path'
import { CHAIN_IDS, type Chain } from './chains'
import type { TokenData, TokenList, TokenListToken } from './types'

const DATA_DIR = path.join(__dirname, '..', 'data');
const OUTPUT_FILE = path.join(__dirname, '..', 'megaeth.tokenlist.json');
const LOGO_BASE_URL = 'https://raw.githubusercontent.com/megaeth-labs/mega-tokenlist/main/data';
const DATA_DIR = path.join(__dirname, '..', 'data')
const OUTPUT_FILE = path.join(__dirname, '..', 'megaeth.tokenlist.json')
const LOGO_BASE_URL =
'https://raw.githubusercontent.com/megaeth-labs/mega-tokenlist/main/data'

function getLogoExtension(tokenDir: string): string | null {
const svgPath = path.join(tokenDir, 'logo.svg');
const pngPath = path.join(tokenDir, 'logo.png');
const svgPath = path.join(tokenDir, 'logo.svg')
const pngPath = path.join(tokenDir, 'logo.png')

if (fs.existsSync(svgPath)) return 'svg';
if (fs.existsSync(pngPath)) return 'png';
return null;
if (fs.existsSync(svgPath)) return 'svg'
if (fs.existsSync(pngPath)) return 'png'
return null
}

function readTokenData(symbol: string): TokenData {
const dataPath = path.join(DATA_DIR, symbol, 'data.json');
const content = fs.readFileSync(dataPath, 'utf-8');
return JSON.parse(content) as TokenData;
const dataPath = path.join(DATA_DIR, symbol, 'data.json')
const content = fs.readFileSync(dataPath, 'utf-8')
return JSON.parse(content) as TokenData
}

export function generate(): TokenList {
// Read all token directories
const tokenDirs = fs
.readdirSync(DATA_DIR)
.filter((name) => {
const stat = fs.statSync(path.join(DATA_DIR, name));
return stat.isDirectory();
const stat = fs.statSync(path.join(DATA_DIR, name))
return stat.isDirectory()
})
.sort();
.sort()

const tokens: TokenListToken[] = [];
const tokens: TokenListToken[] = []

for (const symbol of tokenDirs) {
const tokenDir = path.join(DATA_DIR, symbol);
const tokenData = readTokenData(symbol);
const logoExt = getLogoExtension(tokenDir);
const tokenDir = path.join(DATA_DIR, symbol)
const tokenData = readTokenData(symbol)
const logoExt = getLogoExtension(tokenDir)

// Create token entries for each chain
for (const [chain, chainToken] of Object.entries(tokenData.tokens)) {
if (!chainToken?.address) continue;
if (!chainToken?.address) continue

const chainId = CHAIN_IDS[chain as Chain];
if (!chainId) continue;
const chainId = CHAIN_IDS[chain as Chain]
if (!chainId) continue

const token: TokenListToken = {
chainId,
Expand All @@ -53,23 +54,27 @@ export function generate(): TokenList {
symbol: tokenData.symbol,
decimals: tokenData.decimals,
extensions: chainToken.bridge
? { isNative: false, bridgeAddress: chainToken.bridge, bridgeType: 'canonical' as const }
? {
isNative: false,
bridgeAddress: chainToken.bridge,
bridgeType: 'canonical' as const,
}
: { isNative: true },
};
}

if (logoExt) {
token.logoURI = `${LOGO_BASE_URL}/${symbol}/logo.${logoExt}`;
token.logoURI = `${LOGO_BASE_URL}/${symbol}/logo.${logoExt}`
}

tokens.push(token);
tokens.push(token)
}
}

// Sort tokens by chainId, then symbol
tokens.sort((a, b) => {
if (a.chainId !== b.chainId) return a.chainId - b.chainId;
return a.symbol.localeCompare(b.symbol);
});
if (a.chainId !== b.chainId) return a.chainId - b.chainId
return a.symbol.localeCompare(b.symbol)
})

const tokenList: TokenList = {
name: 'MegaETH Token List',
Expand All @@ -80,14 +85,14 @@ export function generate(): TokenList {
patch: 0,
},
tokens,
};
}

return tokenList;
return tokenList
}

// Main execution
if (require.main === module) {
const tokenList = generate();
fs.writeFileSync(OUTPUT_FILE, JSON.stringify(tokenList, null, 2));
console.log(`Generated ${OUTPUT_FILE} with ${tokenList.tokens.length} tokens`);
const tokenList = generate()
fs.writeFileSync(OUTPUT_FILE, JSON.stringify(tokenList, null, 2))
console.log(`Generated ${OUTPUT_FILE} with ${tokenList.tokens.length} tokens`)
}
Loading