Skip to content

feat: v0.6.0 — per-chain token subpath exports + ERC-20/Chainlink events#12

Merged
chrisli30 merged 4 commits into
mainfrom
feat/v0.6.0-subpath-exports-erc20-extensions
Jun 7, 2026
Merged

feat: v0.6.0 — per-chain token subpath exports + ERC-20/Chainlink events#12
chrisli30 merged 4 commits into
mainfrom
feat/v0.6.0-subpath-exports-erc20-extensions

Conversation

@chrisli30

Copy link
Copy Markdown
Member

Summary

  • Adds @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 root Tokens namespace (~71 KB).
  • Adds Protocols.erc20.{transferAbi, symbolAbi, decimalsAbi, transferEventAbi, eventTopics.Transfer} and Protocols.chainlink.{answerUpdatedEventAbi, eventTopics.AnswerUpdated} so downstream SDK tests and templates can drop hand-rolled ABI fragments.
  • Declares "sideEffects": false so bundlers can tree-shake unused protocol modules.
  • Backward-compatible: root import { Tokens, lookupToken } from "@avaprotocol/protocols" works unchanged.

What's new

Per-chain modules — ethereum, sepolia, base, base-sepolia, bnb-mainnet:

import { tokens, chainId } from "@avaprotocol/protocols/tokens/sepolia";
const usdc = tokens.USDC?.address;

ERC-20 additions on Protocols.erc20:

  • transferAbi / symbolAbi / decimalsAbi — single-fragment function ABIs
  • transferEventAbi — Transfer event ABI for log decoding
  • eventTopics.Transfer0xddf252ad… (pre-computed keccak256)

Chainlink additions on Protocols.chainlink:

  • answerUpdatedEventAbi — AnswerUpdated event ABI
  • eventTopics.AnswerUpdated0x0559884f…

Why

Surveying ava-sdk-js for protocols adoption surfaced ~18 hardcoded address occurrences and 9 inline ABI fragments across 10 test files. The bundle-size concern with the root Tokens namespace blocks SDK-side adoption (the SDK runs in browsers); per-chain subpaths unblock it. The new ABI/topic fields cover the ERC-20 transfer/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/protocols dep from ^0.2.0^0.6.0 and migrate the test files.

Implementation notes

  • tsup migrated from CLI args to tsup.config.ts so the multi-entry build (6 entries) stays single-sourced.
  • tsc -p tsconfig.build.json already emits per-file .d.ts, so every per-chain subpath gets typed.
  • src/tokens/per-chain.ts holds the shared buildChainTokenMap() so each per-chain module is a thin wrapper.
  • Per-chain modules and the root Tokens namespace read the same JSON files; the cross-validation test asserts they agree entry-by-entry.

Bundle sizes (ESM)

Module Size
tokens/sepolia 1.64 KB
tokens/base-sepolia 1.42 KB
tokens/bnb-mainnet 1.35 KB
tokens/base 12.91 KB
tokens/ethereum 26.71 KB
root index (all chains + protocols) 71.24 KB

Test plan

  • yarn build — emits 6 entries (CJS + ESM) plus per-chain .d.ts
  • yarn typecheck — clean
  • yarn test:run — 57 tests pass (28 → 57; +26 per-chain suite, +4 catalog ABI/topic assertions)
  • Bump consumer (ava-sdk-js) in a follow-up PR; verify import path resolves in both Node and browser bundlers

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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 shared buildChainTokenMap() helper and a new per-chain test suite.
  • Extends Protocols.erc20 and Protocols.chainlink with additional ABI fragments and eventTopics constants, 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 thread src/tokens/per-chain.ts Outdated
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);
}
chrisli30 added 3 commits June 6, 2026 18:06
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).
@chrisli30 chrisli30 merged commit f81f84b into main Jun 7, 2026
6 checks passed
@chrisli30 chrisli30 deleted the feat/v0.6.0-subpath-exports-erc20-extensions branch June 7, 2026 01:34
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants