Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
9 changes: 9 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ module.exports = {
parserOptions: {
ecmaVersion: 12,
},
overrides: [
{
files: ["scripts/**/*.mjs"],
rules: {
"node/no-unsupported-features/es-builtins": ["error", { version: ">=16.0.0" }],
"node/no-unsupported-features/node-builtins": ["error", { version: ">=16.0.0" }],
},
},
],
rules: {
"node/no-unsupported-features/es-syntax": ["error", { ignores: ["modules"] }],
"@typescript-eslint/no-var-requires": 0,
Expand Down
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: CI

on:
pull_request:
push:
branches: [master]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v3
with:
node-version: "22.18.0"

- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Lint
run: yarn lint

- name: Build
run: yarn build

- name: Verify legacy equivalence
run: yarn verify:legacy-equivalence

- name: Verify generated files are up to date
run: |
if ! git diff --exit-code src/; then
echo "::error::Generated files are out of date. Run 'yarn build' and commit the result."
git diff src/
exit 1
fi
5 changes: 4 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ jobs:
- name: Build
run: yarn build

- name: Verify legacy equivalence
run: yarn verify:legacy-equivalence

- name: Update npm
run: npm install -g npm@latest

Expand Down Expand Up @@ -74,4 +77,4 @@ jobs:

- name: Publish tagged version
if: steps.release.outputs.tag != ''
run: npm publish --tag ${{ steps.release.outputs.tag }}
run: npm publish --tag ${{ steps.release.outputs.tag }}
1 change: 0 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"printWidth": 120,
"bracketSpacing": true,
"explicitTypes": "preserve",
"tabWidth": 2,
"overrides": [
{
Expand Down
120 changes: 85 additions & 35 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,74 +5,124 @@ This repository contains `@across-protocol/constants` — a shared library expor
## How to use docs in this repo

1. This file (`AGENTS.md`) for navigation and conventions.
2. `src/index.ts` re-exports everything from `networks.ts` and `tokens.ts`.
2. `data/constants.v1.json` is the canonical source of truth.
3. `schema/constants.v1.schema.json` defines the canonical JSON contract.
4. `src/index.ts` re-exports the backward-compatible legacy TypeScript surface.
5. `src/canonical.ts` exposes the canonical TypeScript wrapper.

## Documentation maintenance

Update this `AGENTS.md` when new source files are added or the build/publish process changes.
Update this `AGENTS.md` when the source-of-truth files, generation flow, or publish process changes.

## Quick index

- Entry point: `src/index.ts`
- Network/chain definitions: `src/networks.ts`
- Token mappings and metadata: `src/tokens.ts`
- Build output: `dist/` (cjs, esm, types)
- Canonical source data: `data/constants.v1.json`
- Canonical schema: `schema/constants.v1.schema.json`
- Legacy package entry point: `src/index.ts`
- Canonical TS wrapper: `src/canonical.ts`
- Generated canonical TS types: `src/generated/canonical-types.ts`
- Generated canonical TS runtime module: `src/generated/constants.v1.ts`
- Generated legacy networks: `src/networks.ts`
- Generated legacy tokens: `src/tokens.ts`
- Validation script: `scripts/validate-canonical.mjs`
- Canonical runtime generator: `scripts/generate-canonical-module.mjs`
- Legacy generator: `scripts/generate-legacy.mjs`
- Upstream equivalence check: `scripts/verify-legacy-equivalence.mjs`
- Build output: `dist/`
- CI workflow: `.github/workflows/ci.yml`
- Publish workflow: `.github/workflows/publish.yml`

## Source files

| File | Purpose | Key exports |
| ----------------- | ------------------ | ---------------------------------------------------------------------------------------------- |
| `src/index.ts` | Barrel re-export | Re-exports `networks` and `tokens` |
| `src/networks.ts` | Chain ID constants | Testnet and mainnet chain IDs, chain metadata (~620 lines) |
| `src/tokens.ts` | Token definitions | `TOKEN_SYMBOLS_MAP` with name, symbol, decimals, per-chain addresses, coingeckoId (~730 lines) |
| File | Purpose | Key exports / outputs |
| --------------------------------------- | -------------------------------------------- | --------------------------------------------------------- |
| `data/constants.v1.json` | Canonical source of truth | Chains, networks, tokens, token equivalence mappings |
| `schema/constants.v1.schema.json` | Canonical JSON Schema | Structural contract for canonical data |
| `src/index.ts` | Barrel re-export | Re-exports legacy `networks` and `tokens` |
| `src/canonical.ts` | Canonical TypeScript wrapper | `CONSTANTS_V1` and canonical TS type exports |
| `src/generated/canonical-types.ts` | Generated canonical TS types | Schema-derived canonical interfaces and unions |
| `src/generated/constants.v1.ts` | Generated canonical TS runtime module | Runtime value backing `src/canonical.ts` |
| `src/networks.ts` | Generated legacy chain/network definitions | Legacy chain IDs, enum, network maps |
| `src/tokens.ts` | Generated legacy token definitions | Legacy token metadata map and token equivalence remapping |
| `scripts/validate-canonical.mjs` | Canonical validation | AJV schema validation plus semantic invariants |
| `scripts/generate-canonical-module.mjs` | Canonical JSON -> TS runtime generator | Regenerates `src/generated/constants.v1.ts` |
| `scripts/generate-legacy.mjs` | Canonical -> legacy TS generator | Regenerates `src/networks.ts` and `src/tokens.ts` |
| `scripts/verify-legacy-equivalence.mjs` | Local vs upstream legacy compatibility check | Verifies built root exports match pinned upstream package |

## Directory tree

```text
constants/
json-constants/
├── data/
│ └── constants.v1.json
├── schema/
│ └── constants.v1.schema.json
├── src/
│ ├── index.ts # Barrel export
│ ├── networks.ts # Chain/network definitions
│ └── tokens.ts # Token metadata and addresses
├── dist/ # Build output (generated)
│ ├── cjs/ # CommonJS build
│ ├── esm/ # ES Modules build
│ └── types/ # TypeScript declarations
├── package.json # @across-protocol/constants, Yarn
├── tsconfig.json # TypeScript config (strict, ES5 target)
├── .eslintrc.cjs # ESLint config
├── .prettierrc # Prettier (120 printWidth)
└── .github/workflows/publish.yml # NPM publish on GitHub release
│ ├── canonical.ts
│ ├── generated/
│ │ ├── constants.v1.ts
│ │ └── canonical-types.ts
│ ├── index.ts
│ ├── networks.ts
│ └── tokens.ts
├── scripts/
│ ├── generate-canonical-module.mjs
│ ├── generate-legacy.mjs
│ ├── validate-canonical.mjs
│ └── verify-legacy-equivalence.mjs
├── dist/
│ ├── cjs/
│ ├── esm/
│ └── types/
├── package.json
├── tsconfig.json
├── .eslintrc.cjs
├── .prettierrc
└── .github/workflows/
├── ci.yml
└── publish.yml
```

## Build and test

```bash
# Build (CJS + ESM + types)
# Build generated sources and package outputs
yarn build

# Lint
yarn lint

# Auto-fix
yarn lint-fix
# Compare built legacy exports to the pinned upstream package
yarn verify:legacy-equivalence
```

There are no tests — this is a pure data library.
There are no application tests. The important verification gate is `verify:legacy-equivalence`, which ensures the generated legacy API matches the published upstream legacy package.

## Adding new tokens or networks
## Updating constants

1. **New network**: Add chain ID constant to `src/networks.ts`.
2. **New token**: Add entry to `TOKEN_SYMBOLS_MAP` in `src/tokens.ts` with name, symbol, decimals, per-chain addresses, and coingeckoId.
3. Run `yarn lint-fix` and `yarn build` to verify.
For normal constant additions or value changes, edit only `data/constants.v1.json`.

Update `schema/constants.v1.schema.json` only when the shape changes, for example a new field, a type change, or a new enum value.

Recommended flow:

1. Edit `data/constants.v1.json`.
2. If the shape changed, update `schema/constants.v1.schema.json`.
3. Run `yarn build`.
4. Run `yarn verify:legacy-equivalence`.

Do not edit `src/generated/canonical-types.ts`, `src/generated/constants.v1.ts`, `src/networks.ts`, or `src/tokens.ts` by hand.

## Publish process

- Published to npm via GitHub Actions on GitHub release.
- Workflow validates semver, builds, and publishes with OIDC trusted publishing.
- Pre-release versions supported for beta/canary tags.
- `yarn build` validates canonical data, regenerates canonical and legacy TypeScript sources, and builds package outputs.
- Canonical JSON and schema are published as package artifacts.
- The root package API remains the legacy TypeScript surface for backward compatibility.
- The `./canonical` export exposes the canonical TypeScript wrapper.

## Consumers

This package is consumed by: relayer, indexer, frontend, and toolkit.
- Existing TypeScript consumers should continue using the root package exports.
- TypeScript consumers that want the language-agnostic shape can use `@across-protocol/constants/canonical`.
- Non-TypeScript consumers should consume `data/constants.v1.json` against `schema/constants.v1.schema.json`.
81 changes: 62 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@

Shared library exporting network, token, and address definitions used across the Across Protocol ecosystem.

This package now has two public surfaces:

- The root package, `@across-protocol/constants`, which preserves the existing TypeScript legacy API.
- A canonical language-agnostic contract consisting of:
- `data/constants.v1.json`
- `schema/constants.v1.schema.json`
- `@across-protocol/constants/canonical`

## Installation

```bash
Expand All @@ -16,44 +24,79 @@ yarn add @across-protocol/constants

## Usage

```typescript
import { TOKEN_SYMBOLS_MAP } from "@across-protocol/constants";
Legacy TypeScript surface:

```ts
import { TOKEN_SYMBOLS_MAP } from "@across-protocol/constants"

const usdc = TOKEN_SYMBOLS_MAP.USDC
console.log(usdc.decimals)
console.log(usdc.addresses[1])
```

Canonical TypeScript surface:

// Access token metadata
const usdc = TOKEN_SYMBOLS_MAP.USDC;
console.log(usdc.decimals); // 6
console.log(usdc.addresses[1]); // Ethereum mainnet address
```ts
import { CONSTANTS_V1 } from "@across-protocol/constants/canonical"

const mainnet = CONSTANTS_V1.networks.find((network) => network.chainId === 1)
console.log(mainnet?.name)
```

## What's Exported
## Package Layout

| Surface | Description |
| -------------------------------------- | -------------------------------------------------- |
| `@across-protocol/constants` | Backward-compatible legacy TypeScript exports |
| `@across-protocol/constants/canonical` | Canonical TypeScript wrapper around canonical JSON |
| `data/constants.v1.json` | Canonical source of truth |
| `schema/constants.v1.schema.json` | Canonical JSON Schema |

| Module | Description |
|--------|-------------|
| `networks` | Chain ID constants for testnets and mainnets, chain metadata |
| `tokens` | `TOKEN_SYMBOLS_MAP` — token name, symbol, decimals, per-chain addresses, coingeckoId |
The canonical JSON is the source of truth. The legacy root TypeScript exports are generated from it during `yarn build`.

## Development

```bash
# Build (CJS + ESM + TypeScript declarations)
# Build generated sources and package outputs
yarn build

# Lint
yarn lint

# Auto-fix lint issues
yarn lint-fix
# Check canonical data against the published upstream legacy package
yarn verify:legacy-equivalence
```

## Adding Tokens or Networks
## Updating Constants

Most updates only require editing `data/constants.v1.json`.

Edit `schema/constants.v1.schema.json` only when the shape changes, for example:

- adding a new field
- changing a field type
- adding a new enum value
- making a required field optional, or the reverse

Typical update flow:

1. Edit `data/constants.v1.json`.
2. If the data shape changed, update `schema/constants.v1.schema.json`.
3. Run `yarn build`.
4. Run `yarn verify:legacy-equivalence`.

Do not edit generated files in `src/generated/`, `src/networks.ts`, or `src/tokens.ts` by hand.

## Validation And Generation

1. **New network**: Add chain ID constant to `src/networks.ts`.
2. **New token**: Add entry to `TOKEN_SYMBOLS_MAP` in `src/tokens.ts`.
3. Run `yarn lint-fix && yarn build` to verify.
- Canonical JSON is validated with `ajv`.
- Canonical TypeScript types are generated from JSON Schema with `json-schema-to-typescript`.
- The canonical TypeScript runtime module is generated from `data/constants.v1.json`.
- Legacy TypeScript exports are generated from canonical JSON by `scripts/generate-legacy.mjs`.

## Publishing

Published to npm automatically via GitHub Actions on [GitHub release](https://github.com/across-protocol/constants/releases). Supports pre-release versions for beta/canary tags.
Published to npm automatically via GitHub Actions on [GitHub release](https://github.com/across-protocol/json-constants/releases). Pre-release versions are supported for beta/canary tags.

## License

Expand Down
Loading
Loading