LLMs.txt: agent-readable Markdown index of this site at /llms.txt

TJAR Overview

Learn how TJAR accumulates protocol fees in any asset and converts them into a single chosen token through permissionless releases.

TJAR is a pair of immutable contracts that turn fees collected in many assets into a single token. A Token Jar accumulates whatever its fee sources send it. A Releaser releases the jar's contents to any searcher who sends a fixed amount of a token the jar's operator chooses.

Any protocol that collects fees in mixed assets can use TJAR without running its own trading operations. The jar does not care where assets come from, and the releaser does not care what the chosen token is or what happens to it afterward.

Uniswap uses the same primitive for its own protocol fees, where the chosen token is UNI and the destination is a burn address. That deployment is documented separately in Uniswap Protocol Fees.

Flow of Assets

in:   fee sources ──▶ Token Jar
      any ERC-20 or native asset, from any number of sources

out:  a searcher calls release() on the Releaser
        sends  threshold        ──▶  resource recipient
        sends  protocol fee     ──▶  fee recipient  (only if one is set)
        takes  the named assets ──▶  a recipient the searcher chooses

The jar holds assets and never prices them. The releaser sets one price for the whole jar and lets anyone take the trade.

Components

ContractRole
Token JarCollects fees. Authorizes exactly one releaser at a time and has no other way out.
ReleaserReleases the jar's assets to a searcher who sends a fixed threshold of a chosen resource token.
Fee ControllerChain-wide singleton for an optional protocol fee. No fee is set today. Owned by the Uniswap DAO governance.
FactoryDeploys a jar and releaser together, hands both to the operator, and retains no authority.

How a Release Works

  1. Fee sources send assets to the jar. Nothing is emitted and nothing is recorded: the jar's holdings are exactly its balances.
  2. A searcher decides which of those assets are worth taking and calls release(nonce, assets, recipient, maxFee) on the releaser.
  3. The releaser pulls threshold of the resource token from the searcher to the resource recipient, plus the protocol fee to the fee recipient if one is set.
  4. The jar transfers its full balance of every named asset to the recipient the searcher chose.

A release is profitable when

value(the assets named)  >  threshold + gas

No oracle sets the price. The threshold moves only when the operator changes it, and a protocol fee, if one is ever set, is read from the Fee Controller at execution time.

The release threshold is static:

  • A jar gets more profitable the longer nobody sweeps it. The price does not rise with the contents. The first searcher who finds a jar profitable clears it, so searchers compete on the smallest margin they will accept.
  • A searcher sends the full threshold regardless of how many assets they name. Naming fewer assets does not make a release cheaper. It only leaves value behind for whoever comes next.

Who Can Change What

PartyCan changeCannot change
Jar ownerWhich releaser the jar authorizes, through setReleaser. Can transfer ownership of the jar.Any deployed contract's code
Releaser ownerThe release terms through setConfig, and who holds the configSetter role through setConfigSetter. Can transfer ownership of the releaser.Which releaser the jar authorizes
configSetter, if appointedThe release terms onlyWho holds the configSetter role, ownership of the releaser, and which releaser the jar authorizes
Uniswap governanceThe protocol fee and its recipient. Can transfer ownership of the Fee Controller.Anything about an operator's jar or releaser

The Factory hands ownership of both contracts to the same address at deployment, so the first two rows start as one party. Every ownership transfer is single-step, so a transfer to the wrong address is final.

Release terms are resource, resourceRecipient, threshold, and maxReleaseLength, and they change only together through a single setConfig call. Every such call advances a nonce, so a release priced against terms that have since moved reverts rather than executing.

An operator can also give up control permanently. Deploying with the owner set to 0xdead and no configSetter freezes the pair completely: the terms, the recipients, and the wiring between jar and releaser can never change again.

Security

TJAR has been reviewed by OpenZeppelin, as a diff against the upstream Uniswap protocol fee contracts it derives from. That upstream code carries three further OpenZeppelin reviews and one by Cantina. All reports are listed in Resources.

Deployments

The Factory and the Fee Controller sit at the same address on every chain, and an operator deploying from the same account with the same salt gets the same jar address on every chain. Key everything by chain id and address, never by address alone. See Deployments.

Where to Go Next