feat: v0.6.0 — per-chain token subpath exports + ERC-20/Chainlink events#12
Merged
Merged
Conversation
Adds `@avaprotocol/protocols/tokens/<chain>` subpath exports so
consumers that only need one chain's tokens can import a single ~1-30
KB module instead of pulling all five chains via the root `Tokens`
namespace (currently ~71 KB). Also declares `sideEffects: false` so
bundlers can tree-shake unused protocol modules.
Surface added:
- `import { tokens, chainId } from "@avaprotocol/protocols/tokens/sepolia"`
Available for ethereum, sepolia, base, base-sepolia, bnb-mainnet.
Each module exports `chainId` (number) and a frozen, symbol-keyed
`tokens: Record<string, TokenChainEntry>`.
- `Protocols.erc20.transferAbi` / `symbolAbi` / `decimalsAbi` /
`transferEventAbi` / `eventTopics.Transfer`. Lets downstream SDK
tests and templates drop hand-rolled ABI fragments and topic hashes.
- `Protocols.chainlink.answerUpdatedEventAbi` /
`eventTopics.AnswerUpdated`. Same motivation — the AnswerUpdated
event was being re-derived in ava-sdk-js's eventTrigger test.
Implementation notes:
- tsup migrated from CLI args to `tsup.config.ts` so the multi-entry
build (6 entries) stays single-sourced and reviewable.
- `tsc -p tsconfig.build.json` already emits per-file `.d.ts`, so
every per-chain subpath gets typed.
- Root `import { Tokens, lookupToken } from "@avaprotocol/protocols"`
works unchanged — additive change, no consumer disruption.
Bundle size per `dist/tokens/*.js` (ESM):
sepolia 1.64 KB
base-sepolia 1.42 KB
bnb-mainnet 1.35 KB
base 12.91 KB
ethereum 26.71 KB
vs. root index 71.24 KB
Tests: 28 → 57 (added 26-test per-chain suite + 4 catalog assertions
covering the new ABI/topic fields). All green.
There was a problem hiding this comment.
Pull request overview
This PR introduces new per-chain token subpath entrypoints and expands the shared protocol catalog with commonly reused ERC-20 and Chainlink event ABI fragments and precomputed topic hashes, aiming to improve consumer bundle size and reduce duplicated ABI/topic constants.
Changes:
- Adds per-chain token modules (
@avaprotocol/protocols/tokens/<chain>) plus a sharedbuildChainTokenMap()helper and a new per-chain test suite. - Extends
Protocols.erc20andProtocols.chainlinkwith additional ABI fragments andeventTopicsconstants, with new catalog assertions. - Migrates the JS build to
tsup.config.ts, adds package subpath exports for the new token modules, and declares"sideEffects": false.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
tsup.config.ts |
Configures multi-entry tsup builds to emit per-chain token bundles. |
package.json |
Adds subpath exports for per-chain token modules and sets sideEffects: false; switches build:js to tsup config. |
src/tokens/per-chain.ts |
Adds shared helper for building frozen per-chain token maps from JSON rows. |
src/tokens/ethereum.ts |
Adds Ethereum per-chain token subpath module. |
src/tokens/sepolia.ts |
Adds Sepolia per-chain token subpath module. |
src/tokens/base.ts |
Adds Base per-chain token subpath module. |
src/tokens/base-sepolia.ts |
Adds Base Sepolia per-chain token subpath module. |
src/tokens/bnb-mainnet.ts |
Adds BNB Chain mainnet per-chain token subpath module. |
src/protocols/erc20.ts |
Adds ERC-20 transfer/symbol/decimals ABIs, Transfer event ABI, and topic hash constant. |
src/protocols/chainlink.ts |
Adds Chainlink AnswerUpdated event ABI and topic hash constant. |
tests/per-chain.test.ts |
Adds tests validating per-chain modules match root Tokens and are frozen. |
tests/catalog.test.ts |
Adds assertions for new ERC-20/Chainlink ABI fragments and topic hashes. |
.changeset/v0_6_0-subpath-exports-erc20-chainlink-events.md |
Documents the new subpaths, sideEffects flag, and ABI/topic additions for the minor release. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+30
to
+40
| const out: Record<string, TokenChainEntry> = {}; | ||
| for (const row of rows) { | ||
| const { symbol, ...entry } = row; | ||
| if (out[symbol]) { | ||
| throw new Error( | ||
| `[@avaprotocol/protocols] duplicate symbol "${symbol}" in ${sourceLabel} — ` + | ||
| `each symbol must appear once per chain file.`, | ||
| ); | ||
| } | ||
| out[symbol] = Object.freeze(entry); | ||
| } |
Copilot review of #12 flagged `buildChainTokenMap` for using plain `{}` + truthy/`in` checks to detect duplicate symbols — a curated catalog shouldn't contain `__proto__`/`toString` symbols, but the defense is free and the data is parsed externally. - `src/tokens/per-chain.ts`: backing map is `Object.create(null)`; duplicate detection uses `Object.prototype.hasOwnProperty.call`. - `src/tokens/index.ts`: same hardening applied to the pre-existing `buildTokensFromData` aggregator — same construct, same risk. Tests unchanged (57 pass).
6 tasks
chrisli30
added a commit
that referenced
this pull request
Jun 9, 2026
The root `Tokens` namespace used to import each chain's JSON directly and re-run the per-row → symbol-keyed transform. That duplicated the transform the per-chain modules already perform at their own module load: two code paths reading the same source files. After this change, `src/tokens/index.ts` consumes the per-chain modules (`./ethereum`, `./sepolia`, `./base`, `./base-sepolia`, `./bnb-mainnet`) as its source of truth. Per-chain modules stay the canonical typed access for chain-bound consumers (via the existing subpath exports added in 0.6.0); the root `Tokens` becomes a pure flatten over their pre-validated symbol → entry maps. Behavior preserved: - Public surface unchanged: `Tokens.SYMBOL[chainId]`, `lookupToken()`, and the per-chain subpath exports all keep working identically. - The cross-validation test in `tests/per-chain.test.ts` becomes a tautology (same source flowing through both paths), but stays valid as a regression guard if anyone changes the aggregator. - Null-prototype + own-property-check hardening from #12 carried through; the (symbol, chainId) duplicate check is dropped because per-chain modules already guarantee single-symbol-per-chain at their own load — the aggregator's slot is always empty. All 57 tests still pass. Build emits the same six entries and the same five JSON sidecars.
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@avaprotocol/protocols/tokens/<chain>subpath exports so consumers that only need one chain's tokens ship a ~1–30 KB module instead of pulling all five via the rootTokensnamespace (~71 KB).Protocols.erc20.{transferAbi, symbolAbi, decimalsAbi, transferEventAbi, eventTopics.Transfer}andProtocols.chainlink.{answerUpdatedEventAbi, eventTopics.AnswerUpdated}so downstream SDK tests and templates can drop hand-rolled ABI fragments."sideEffects": falseso bundlers can tree-shake unused protocol modules.import { Tokens, lookupToken } from "@avaprotocol/protocols"works unchanged.What's new
Per-chain modules —
ethereum,sepolia,base,base-sepolia,bnb-mainnet:ERC-20 additions on
Protocols.erc20:transferAbi/symbolAbi/decimalsAbi— single-fragment function ABIstransferEventAbi— Transfer event ABI for log decodingeventTopics.Transfer—0xddf252ad…(pre-computed keccak256)Chainlink additions on
Protocols.chainlink:answerUpdatedEventAbi— AnswerUpdated event ABIeventTopics.AnswerUpdated—0x0559884f…Why
Surveying
ava-sdk-jsfor protocols adoption surfaced ~18 hardcoded address occurrences and 9 inline ABI fragments across 10 test files. The bundle-size concern with the rootTokensnamespace blocks SDK-side adoption (the SDK runs in browsers); per-chain subpaths unblock it. The new ABI/topic fields cover the ERC-20transfer/symbol/decimals+ Transfer-event surface and Chainlink AnswerUpdated, which the SDK currently re-derives inline.Follow-up PR will bump
ava-sdk-js's@avaprotocol/protocolsdep from^0.2.0→^0.6.0and migrate the test files.Implementation notes
tsupmigrated from CLI args totsup.config.tsso the multi-entry build (6 entries) stays single-sourced.tsc -p tsconfig.build.jsonalready emits per-file.d.ts, so every per-chain subpath gets typed.src/tokens/per-chain.tsholds the sharedbuildChainTokenMap()so each per-chain module is a thin wrapper.Tokensnamespace read the same JSON files; the cross-validation test asserts they agree entry-by-entry.Bundle sizes (ESM)
tokens/sepoliatokens/base-sepoliatokens/bnb-mainnettokens/basetokens/ethereumindex(all chains + protocols)Test plan
yarn build— emits 6 entries (CJS + ESM) plus per-chain.d.tsyarn typecheck— cleanyarn test:run— 57 tests pass (28 → 57; +26 per-chain suite, +4 catalog ABI/topic assertions)