Skip to content

refactor(deps): source BN from anchor and drop unused @types/bn.js - #688

Open
amilz wants to merge 5 commits into
mainfrom
refactor/DEV-839-anchor-kit-codecs
Open

refactor(deps): source BN from anchor and drop unused @types/bn.js#688
amilz wants to merge 5 commits into
mainfrom
refactor/DEV-839-anchor-kit-codecs

Conversation

@amilz

@amilz amilz commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Completes DEV-839 — all five sections. Five commits, each a self-contained change.

borsh is now absent from the entire repository.

1. refactor(deps) — source BN from Anchor, drop unused @types/bn.js

17 test files imported BN directly from bn.js while declaring only @types/bn.js, resolving the runtime package transitively. @anchor-lang/core re-exports BN and depends on bn.js itself, so these now use anchor.BN — already the dominant idiom, since sibling litesvm.test.ts files in the same packages used it while test.ts used a bare BN. Two packages also dropped a direct bn.js dependency that no longer has a direct importer.

Beyond tidiness this removes a real footgun: under pnpm a test's own bn.js copy can be a physically distinct module from the one Anchor's coder uses, breaking instanceof during serialization. anchor.BN guarantees class identity.

@types/bn.js was removed from 16 packages and deliberately kept in 12. bn.js ships no type declarations, so @types/bn.js is the only supplier of the BN type that Anchor maps u64/i64/u128/i128 IDL fields to, and @anchor-lang/core declares it only as a devDependency. Removing it does not fail the build — every tsconfig sets skipLibCheck: true, which swallows the missing declaration and silently widens BN to any:

const x: anchor.BN = 'definitely not a BN';
// with @types/bn.js:    error TS2322
// without:              compiles clean

That would have quietly un-typed every 64-bit IDL field (basics/counter/anchor calls .toNumber() on a u64). It is retained in the 11 packages whose programs use 64-bit ints, plus allow-block-list-token, which imports BN explicitly in .tsx.

2. refactor(tokens) — decode token accounts with kit codecs

Three litesvm tests used AccountLayout.decode(...) from @solana/spl-token; they now use getTokenDecoder() from @solana-program/token (token-2022 for the Token-2022 example). amount is a bigint from both, so no assertion changed. @solana/spl-token stays — all three still use its instruction builders. Also drops an unused ethers.

Heads-up for reviewers: these are pinned to @solana-program/token@0.15.0, not the 0.14.x used elsewhere. 0.14.x imports getMinimumBalanceForRentExemption from @solana/kit, an export removed in kit 7.1.0; a fresh resolve of ^7.0.0 gets 7.1.0 and fails at import time with a hard SyntaxError. Packages still on 0.14.x work only because their committed lockfiles pin kit at 7.0.0. Not introduced here, but worth a follow-up bump repo-wide.

3. refactor — dead dependencies and the last direct bn.js import

Removes dependencies with no importer across nft-operations/anchor, cnft-burn/anchor, cutils/anchor, and nft-meta-data-pointer/{anchor,app}. Kept deliberately: @metaplex-foundation/js in cnft-burn (it is imported), and Chakra's @emotion/* / framer-motion peers. browserify-sign and crypto-js were version-floor pins rather than real dependencies — crypto-js still resolves to 4.2.0 transitively, and nothing in the tree depends on browserify-sign.

Also replaces the repo's last direct bn.js import: new BN(leaf_id).toArray('le', 8)getU64Encoder().encode(BigInt(leaf_id)).

4. refactor(escrow) — borsh helper to kit struct codecs

Both escrow examples wrapped a local borshSerialize(schema, data) helper. Replaced with getStructEncoder/getStructDecoder matching basics/close-account/native, dropping borsh. Field widths and order were checked against each program's Rust source; the decoder's fixed size of 113 matches Offer::LEN, and the encoder produces 00 0100000000000000 0200000000000000 0300000000000000 ff, matching the offsets make_offer.rs reads.

5. refactor(basics,tokens) — native instruction data via kit codecs

The remaining 12 native/pinocchio examples hand-rolled borsh schemas inline in their tests. Each now exposes a ts/ client module following basics/close-account/native (from DEV-838): encoders and instruction builders under ts/instructions, account decoders under ts/state, and a discriminant map matching the program's instruction enum. Tests import the builders instead of serializing by hand.

Encodings were checked field by field against each program's Rust source. Where a program has no instruction discriminant (account-data, processing-instructions, repository-layout — they deserialize the whole payload), the encoder covers the bare payload rather than inventing a tag. repository-layout/pinocchio was verified independently of its native twin rather than assumed identical; it turned out byte-identical with no discriminant split off.

Several encoders were additionally checked byte-for-byte against borsh.serialize of the equivalent schema — e.g. visitPark('Jimmy', 3)050000004a696d6d7903000000, and the escrow encoder → 00 0100000000000000 0200000000000000 0300000000000000 ff, matching the offsets make_offer.rs reads.

Verification

Local anchor build --ignore-keys + tsc --noEmit + test runs:

Package Result
escrow/native, escrow/pinocchio build + 15 tests passing
token-fundraiser/anchor build + tsc + 9 passing
transfer-switch/anchor build + tsc + 8 passing
external-delegate-token-master/anchor build + tsc + 3 passing
nft-operations/anchor build + tsc + 3 passing
nft-meta-data-pointer/anchor build + tsc
account-data, favorites, transfer-sol, pda-rent-payer, transfer-tokens, token-2022/basics build + tsc

pnpm install --frozen-lockfile verified in every package with a modified package.json, and prettier --check passes on every changed file.

Seven of the section-5 packages could not be tested on my machine — cargo build-sbf under a local solana-cli 4.2.0 produces .so binaries that fail against the pinned litesvm with Access violation ... at address 0x3 after 44 compute units. I confirmed this is environmental rather than a codec bug by restoring basics/account-data/native entirely to main, borsh and all, and rebuilding: it fails identically. Section 5 changed only TypeScript; no Rust source moved. CI (solana 3.1.8) builds and tests all 12 and passes.

compression/cnft-burn/anchor and compression/cutils/anchor have pre-existing type errors (undeclared bs58/@solana/spl-token imports, a stale treeAuthority IDL reference). I confirmed these reproduce unchanged at main and are not caused by these commits; both packages are in .github/.ghaignore, so CI does not build them.

Tests imported BN directly from bn.js while declaring only @types/bn.js,
resolving the runtime package transitively. @anchor-lang/core re-exports
BN and depends on bn.js itself, so these tests can take BN from the
Anchor namespace they already import instead.

- Rewrite 17 test files from a direct bn.js import to anchor.BN
- Drop the now-dead direct bn.js dependency from two packages
- Remove @types/bn.js from 16 packages with no BN in their type surface
- Regenerate the affected per-project lockfiles

@types/bn.js is kept wherever BN is reachable. bn.js ships no type
declarations, so it is the only supplier of the BN type that Anchor maps
u64/i64/u128/i128 IDL fields to; removing it there widens those fields to
any instead of failing, because every tsconfig sets skipLibCheck.
@amilz
amilz requested a review from dev-jodee as a code owner August 14, 2026 18:05
@linear

linear Bot commented Aug 14, 2026

Copy link
Copy Markdown

DEV-839

@greptile-apps

greptile-apps Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR consolidates test-side BN construction on Anchor’s exported BN and removes package-local BN dependencies and declarations considered unreachable.

  • Replaces direct bn.js imports with anchor.BN across Anchor tests.
  • Removes unused @types/bn.js entries and synchronizes per-project lockfiles.
  • Updates the cNFT burn client dependency from Umi to Solana Kit.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains within the eligible follow-up scope.

No blocking failure remains.

Important Files Changed

Filename Overview
basics/favorites/anchor/tests/test.ts Replaces direct BN construction with the existing Anchor namespace export.
tokens/transfer-tokens/anchor/package.json Removes direct BN dependencies after test code was migrated to Anchor’s export.
compression/cnft-burn/anchor/package.json Replaces the direct Umi dependency with Solana Kit and regenerates the corresponding lockfile.
compression/cnft-burn/anchor/tests/ReadApi/WrapperConnection.ts Updates the cNFT wrapper’s type source to match the new Solana Kit dependency.
tokens/token-swap/anchor/tests/utils.ts Sources all test utility BN values through the already imported Anchor namespace.

Reviews (2): Last reviewed commit: "refactor(escrow): replace borsh helper w..." | Re-trigger Greptile

amilz added 4 commits August 14, 2026 11:24
Three litesvm tests decoded SPL token accounts with AccountLayout from
@solana/spl-token. The official program clients expose a decoder for this,
so use getTokenDecoder() from @solana-program/token, or token-2022 for the
Token-2022 example. amount is a bigint from both, so assertions are
unchanged. @solana/spl-token stays: all three still use its instruction
builders.

Also drops the unused ethers dependency from external-delegate-token-master.

The token clients are pinned to 0.15.0 rather than the 0.14.x used
elsewhere in the repo, because 0.14.x imports
getMinimumBalanceForRentExemption from @solana/kit, an export kit removed
in 7.1.0.
Removes dependencies with no importer in their package:

- nft-operations/anchor: @metaplex-foundation/mpl-token-metadata,
  @metaplex-foundation/umi, axios, node-fetch
- cnft-burn/anchor: @metaplex-foundation/umi
- cutils/anchor: @metaplex-foundation/js
- nft-meta-data-pointer/{anchor,app}: @coral-xyz/spl-token,
  browserify-sign, crypto-js, @chakra-ui/next-js

@metaplex-foundation/js is kept in cnft-burn, which does import it, and
Chakra's emotion and framer-motion peers are kept because Chakra needs
them. browserify-sign and crypto-js were version-floor pins rather than
real dependencies: crypto-js still resolves to 4.2.0 transitively, and
nothing in the tree depends on browserify-sign at all.

Also replaces the repository's last direct bn.js import, in cnft-burn's
ReadApi wrapper, where new BN(leaf_id).toArray('le', 8) becomes
getU64Encoder().encode(BigInt(leaf_id)).
Both escrow examples wrapped a local borshSerialize(schema, data) helper
to build instruction data and to decode the Offer account. Replaces it
with getStructEncoder and getStructDecoder, matching the shape already
used in basics/close-account/native, and drops the borsh dependency.

Field widths and order were checked against each program's Rust source.
The decoder's fixed size of 113 matches Offer::LEN, and decoding the
pubkey fields with getAddressDecoder yields Address values directly, so
the tests no longer round-trip them through a raw byte array.
The remaining native and pinocchio examples hand-rolled borsh schemas
inline in their tests to build instruction data and decode their own
program accounts. Each example now exposes a ts/ client module built on
@solana/kit codecs, following basics/close-account/native: instruction
encoders and builders under ts/instructions, account decoders under
ts/state, and a discriminant map matching the program's instruction enum.
Tests import the builders instead of serializing by hand, and borsh is
removed from all twelve packages.

Encodings were checked field by field against each program's Rust source.
Where a program has no instruction discriminant, as in account-data,
processing-instructions and repository-layout, the encoder covers the bare
payload rather than inventing a tag.

Covers the last of the packages carrying borsh, so the repository no
longer depends on it anywhere.
@greptile-apps

greptile-apps Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Too many files changed for review (171 files, 100 file limit).

Bypass the limit by tagging @greptile-apps to review.

@amilz amilz self-assigned this Aug 14, 2026
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.

1 participant