pier2pier docs · plain-language explainer of the protocol mechanics. Learn more
TREASURY · v0.2

The treasury, line by line.

PierTreasury is the contract that holds the protocol's assets between epochs. It's deliberately small and deliberately constrained — by design, it can't do anything interesting except route harvested yield to stakers.

What it holds

  • WETH — briefly, between harvestClankerFees() and swapToGitlawb(). Always destined for the swap.
  • $gitlawb — briefly, between the swap and routeYield(). Always destined for stakers + the fee sink.
  • (Eventually) a fleet of gitlawb nodes' staked $gitlawb — but only after gitlawb mainnet PoS deploys. Today this is zero.

What it can't do

This is the load-bearing claim of the whole protocol. The treasury has an adminWithdraw(token, amount, recipient) function, which sounds scary — but it is constrained at the contract level to only sweep tokens that are NOT $gitlawb and NOT WETH. Try to sweep either and the call reverts with a custom error. We never wrote a code path that lets an admin drain the protocol's revenue.

  • adminWithdraw($gitlawb, …) → reverts CannotSweepGitlawb().
  • adminWithdraw(WETH, …) → reverts CannotSweepWeth().
  • adminWithdraw(otherToken, …) → succeeds. This is the legitimate use: sweeping accidental transfers and unrelated airdrops to the protocol's fee sink.

Six tests in our suite specifically prove this invariant under varied conditions — including with millions of $gitlawb and WETH sitting in the treasury. They're named with the AdminWithdraw_ prefix; we run them in CI.

The fee skim

Each routeYield() call sends a protocolFeeBps share of the harvested $gitlawb to the protocol's fee sink. The default is 1000 bps (10%). The ceiling is hard-coded at 2000 bps (20%) — try to set higher and the transaction reverts. This is not a knob the operator can yank up later.

Roles

  • Owner — sets the keeper, sets the factory, sets the fee sink, sets the fee bps (subject to the cap), registers/unstakes piers when PoS is live. Cannot move stake or staker yield.
  • Keeper — a hot, gas-only wallet. Runs heartbeats, harvests, swaps, claims, routes. Cannot register, unstake, or sweep funds.
  • Factory — an off-chain provisioner wallet. Can only call registerPier. Nothing else. Lets the auto-growth pipeline run unattended without holding the owner key.

The accounting counters

Two cumulative numbers are always readable on Basescan:

  • totalFeesPaid — every $gitlawb ever sent to the fee sink.
  • totalRoutedToStakers — every $gitlawb ever deposited into PierStaking.

Together with PierStaking's totalClaimedYield, you can independently verify what the protocol has paid out vs accumulated, with no trust in our dashboard.

What changes when PoS launches

The treasury has a nodeStaking immutable field that's currently set to address(0). While it's zero, all pier-lifecycle methods (registerPier, heartbeat, claim, unstake, updateUrl) revert with NodeStakingNotConfigured(). The revenue pipeline (harvest, swap, route) is unaffected and runs normally.

On the day gitlawb publishes their mainnet NodeStaking address, the right move is redeploy a fresh PierTreasury with the real address baked in. We don't bolt-on upgrades to a live contract; the new treasury is wired up, Clanker's fee recipient is pointed at it in one tx, and the staker UX is identical (a brief routing pause; PierStaking itself doesn't move).