npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bananapus/distributor-v6

v1.0.0

Published

`@bananapus/distributor-v6` distributes ERC-20 balances or 721 token inventories to many recipients under round-based vesting rules. It is a payout utility package for Juicebox-adjacent flows, not a protocol accounting layer.

Readme

Juicebox Distributor

@bananapus/distributor-v6 distributes ERC-20 balances or 721 token inventories to many recipients under round-based vesting rules. It is a payout utility package for Juicebox-adjacent flows, not a protocol accounting layer.

Documentation

  • ARCHITECTURE.md — system overview, modules, trust boundaries, and core invariants.
  • USER_JOURNEYS.md — end-to-end flows for funders and claimants across token and 721 variants.
  • INVARIANTS.md — per-section invariants for snapshot fairness, vesting math, beneficiary routing, loans, and recycling.
  • RISKS.md — risk register with priority risks and the minimum invariants to verify.
  • ADMINISTRATION.md — deployment parameters, control posture, and recovery guidance.
  • SKILLS.md — quick index for routing tasks into the right sub-document.
  • STYLE_GUIDE.md — Solidity and repo conventions used across the Juicebox V6 ecosystem.
  • AUDIT_INSTRUCTIONS.md — audit framing, targets, and suggested hunting grounds.
  • CHANGELOG.md - V5 to V6 migration changelog.

Overview

This repo provides reusable distributors for teams that need deterministic post-funding or post-mint distribution.

The package separates distribution mechanics by asset type:

  • JBDistributor coordinates shared round and vesting logic
  • JBTokenDistributor distributes ERC-20 balances using IVotes checkpointed voting power
  • JB721Distributor distributes value to active 721 holders using the hook's checkpointed owner and active-vote data, ensuring only holders at the funded round's snapshot block are eligible

Both concrete distributors implement IJBSplitHook, which makes them usable directly from Juicebox payout splits.

Use this repo when the problem is "how do we distribute already-owned assets over time?" Do not use it when the problem is project accounting, treasury settlement, or terminal execution.

If the issue is "where did the project's value come from?" start in nana-core-v6, nana-721-hook-v6, or the upstream repo that minted or received the assets first.

Key contracts

| Contract | Role | | --- | --- | | JBDistributor | Shared round-based vesting, claiming, and accounting logic. | | JBTokenDistributor | ERC-20 distributor keyed to IVotes checkpointed voting power. | | JB721Distributor | NFT-aware distributor keyed to checkpointed voting power from the hook's checkpoint module. Only NFTs held at the funded round's snapshot block are eligible. |

Mental model

  1. a project funds the distributor, often through a payout split
  2. accepted funding is assigned to the current reward round for the chosen token or 721 stake source
  3. each funded reward round records an active-vote snapshot denominator for its token, collection, or tier group
  4. anyone can start vesting completed past reward rounds for an encoded token staker or current NFT owner
  5. anyone can recycle expired reward-round inventory that has not started vesting after the claim deadline
  6. recipients collect their vested share as the configured vesting schedule unlocks; helpers can collect only to the canonical holder
  7. eligible claimants can borrow against vesting revnet rewards without bypassing the vesting schedule
  8. burned 721 rewards can be materialized and recycled through explicit cleanup paths as they vest

This repo does not explain why an allocation exists. It only defines how funded inventory is handed out.

Read these files first

  1. src/interfaces/IJBDistributor.sol
  2. src/JBDistributor.sol
  3. src/JBTokenDistributor.sol
  4. src/JB721Distributor.sol

Integration traps

  • distribution correctness depends on the distributor actually holding the assets it is expected to vest
  • ERC-20 and ERC-721 distributions share historical reward-round accounting, but their canonical beneficiaries differ: token rewards belong to the encoded staker address, while 721 rewards belong to the current NFT owner
  • beginVesting is permissionless because no value leaves the distributor; collectVestedRewards is permissionless only when paid to the canonical beneficiary, while an authorized holder can still choose any beneficiary
  • CLAIM_DURATION is fixed at deployment; 0 means reward rounds do not expire, while nonzero values set the window after which unmaterialized reward inventory can be recycled
  • token distributors record IJBActiveVotes.getPastTotalActiveVotes at the funded round's snapshot block; only addresses with getPastVotes at that block share the pot
  • 721 distributors record the hook checkpoint module's active total for all-tiers rewards, or the summed active totals for a tier-scoped reward group; both modes cap each NFT claim by the snapshot owner's remaining active units for that NFT's tier
  • recycleExpiredRewards is permissionless; it recycles the expired round's unmaterialized remainder while preserving amounts that already started vesting
  • eligible expired and forfeited rewards stay in distributor inventory and are recycled into the current reward round. A reward round never recycles into itself; if the requested round is still current, the call is a no-op, including for zero-stake rounds
  • revnet loan-backed vesting is opt-in at deployment; the reward token must be a REVOwner-owned revnet token, the distributor keeps the loan NFT, and repayment restores the original vesting schedule instead of releasing all collateral immediately
  • if Revnet liquidates a distributor-held vesting loan, anyone can call writeOffLiquidatedVestingLoan to clear the stale collection lock and forfeit only the vesting rewards that were collateralized by that loan
  • distributors deployed with VESTING_ROUNDS == 0 disable revnet vesting loans because rewards are immediately collectible instead of locked in a vesting position
  • releaseForfeitedRewards matters for 721 distributions; it first materializes any unclaimed historical shares for burned NFTs, then recycles only the amount unlocked by the vesting schedule. Token-vote distributions do not have the same burned-token forfeiture path
  • reward, vesting, and loan accounting carries a groupId: 0 is the all-tiers group (the default pool), a non-zero group is keccak256(abi.encode(tierIds)). The tier overloads live on JB721Distributor; the base is tier-agnostic. Split funding via processSplitWith always lands in group 0 — a split cannot carry a tier set; tier-scoped pots require the explicit fund(hook, tierIds, token, amount) overload, and claims/collections must pass the same tierIds to hit that group
  • tier-scoped 721 pots weigh each eligible NFT by its tier's votingUnits against a summed getPastTotalTierActiveVotes denominator, then cap each numerator with getPastAccountTierActiveVotes; this requires @bananapus/721-hook-v6 >= 0.0.73 for the active-vote checkpoints API
  • snapshot timing is part of the trusted surface
  • poke()-style keeper or funding flows should be treated as snapshot policy decisions: calling them at a different block can change which historical votes or NFTs share a funded round
  • 721 claim helpers should preflight the holder, tier set, checkpoint block, and available distributor inventory before batching claims; ownership at the time of submission is not enough if the funded round used an older snapshot
  • direct token or native-token balances at a distributor are unaccounted inventory until an explicit funding or recycle path assigns them to a reward round
  • this repo settles distributions, but it does not prove the upstream entitlement math was correct

Where state lives

  • round and vesting state: JBDistributor
  • historical reward-round inputs: JBRewardRoundData
  • vesting schedule state: JBVestingData
  • asset-specific claim behavior: the concrete distributor

High-signal tests

  1. test/JBTokenDistributor.t.sol
  2. test/JB721Distributor.t.sol
  3. test/invariant/JB721DistributorInvariant.t.sol
  4. test/regression/VestingLoanRegression.t.sol

Install

npm install @bananapus/distributor-v6

Development

npm install
forge build --deny notes
forge test --deny notes

Useful scripts:

  • npm run test:fork
  • npm run deploy:mainnets
  • npm run deploy:testnets

Repository layout

src/
  JBDistributor.sol
  JBTokenDistributor.sol
  JB721Distributor.sol
  interfaces/
  structs/
test/
  token, 721, and invariant coverage
script/
  Deploy.s.sol

Risks and notes

  • distributors are only as trustworthy as the vesting parameters and funding they receive
  • operational mistakes often come from funding the wrong asset or underfunding the distributor
  • teams should review claim timing and snapshot assumptions with the same care they review the payout source
  • token distributors require hooks that expose IJBActiveVotes; expiring token rounds recycle any unmaterialized remainder after the deadline
  • payout-split funding always enters the default reward group; tier-scoped rewards need explicit funding and matching tier-scoped claim parameters

For AI agents

  • Treat this repo as distribution plumbing, not as the source of upstream entitlement math.
  • Read both the ERC-20 and ERC-721 tests before claiming the flows are equivalent.