buds

Mechanics · sheet two of two

how pairing works.

Pairing is a handshake between two wallets, recorded by the hook that sits on the ETH / BUDS pool. It costs nothing to make and nothing to keep. This page is the whole of it — including the parts that are inconvenient.

The handshake

01
01 — Offer
A: proposeBuddy(B) Binds nobody yet
02 — Accept
B: acceptBuddy(A) Both have now spoken
03 — Paired
buddy[A] = B, buddy[B] = A Both buy at the buddy rate

Consent is structural

A pair is only ever formed inside acceptBuddy, and that call requires a matching outstanding proposal from the other side. There is no path that pairs two wallets without both of them having sent a transaction. Nobody can pair you to themselves, drag you into a pair, or intercept somebody else’s proposal — an offer names one specific wallet and only that wallet can take it.

A proposal is not a commitment. You can withdraw yours, you can be proposed to a hundred times and stay single, and a stale offer stops working the moment either side is paired elsewhere.

One bud at a time

Each wallet holds exactly one active buddy. To pair with someone new you have to unpair first, and unpairing has a cost — see below. This is what makes the arrangement mean something: you are choosing one counterpart, not collecting a network.

Nothing is handed over

Pairing moves no tokens. There is nothing to hand over, no approval to grant, and no contract holds your balance. It is two rows in a registry.

What being paired actually does

02
Effect one

A cheaper buy

Every buy pays a cut of the ETH going in. Paired wallets pay the buddy rate instead of the standard rate, decided per swap, at the moment of the swap. Both of you get it, permanently, for as long as you stay paired.

Effect two

Entitlement, halved

The cut a paired buy generates is booked as entitlement, split down the middle between the two buddies. Either one’s trading earns for both. A quiet buddy still earns from an active one.

Effect three

Somebody else pays

Unpaired buys book no entitlement whatsoever. Their cut still lands in the same pot, and the pot is only ever shared among wallets with entitlement — which means paired ones.

Non-effect

Sells are untouched

Selling pays no cut and books no entitlement, paired or not. The mechanism lives entirely on the buy side.

The pot, and how it gets shared

03

The cut is held as a claim

The hook does not transfer the ETH it takes. It mints itself a claim against Uniswap’s PoolManager instead, which means the fee path has no transfer that could fail and therefore no way for a buy to revert because of it.

Anyone can pull the lever

splitPot() is open to anybody. It redeems the claim and, inside a single transaction, market-buys $BUDS with the ETH — through the same pool as everyone else, at the same price. Whoever called it keeps a small tip out of the tokens bought; the rest goes to the escrow.

Three things bound that call: a cooldown between splits, a hard cap on how much ETH one split may spend, and a slippage floor that reverts the whole thing if the market buy comes back short. The cap is deliberately small relative to the pool.

Entitlement only grows

Nothing in the contract reduces a wallet’s entitlement — not unpairing, not claiming, not anybody else’s behaviour. That is a design choice with a purpose: if walking out wiped your buddy’s book, walking out would be a way to rob them.

Payouts are pull, never push

Your share sits in the escrow until you claim it. The split never tries to send tokens to anyone, so a buddy who disappears, or whose wallet stops being able to receive, cannot stall your payout or anybody else’s.

Worked example — illustrative rates only

Two wallets, one afternoon

The real rates have not been chosen. For the sake of arithmetic, suppose the standard rate were 3% and the buddy rate 1%.

  1. Dana and Ola pair: Dana proposes, Ola accepts.
  2. Dana buys with 1 ETH. Her cut is 0.01 ETH instead of 0.03 ETH. The pot gains 0.01 ETH, and Dana and Ola are each booked 0.005 ETH of entitlement — Ola did nothing.
  3. A wallet with no bud buys with 1 ETH and pays 0.03 ETH. The pot gains all of it. Nobody is booked anything for that buy.
  4. Someone — anyone — calls splitPot(). The pot buys $BUDS on the open market. The caller takes a small tip; the rest is escrowed and shared in proportion to entitlement.
  5. Dana and Ola pull their shares whenever they like. The unpaired buyer gets none of it. He paid for it.

Unpairing, and who it costs

04
Know this

Either buddy can unpair. Both go into cooldown.

unpair() takes one call from one side. It does not ask the other one. The pair is dissolved immediately and both wallets are put into the pairing cooldown — the wallet that walked and the wallet that was walked out on, for the same length of time. Neither can pair with anyone new until it expires, and while you are cooling nobody can send you an offer either.

This means somebody can impose a cooldown on you by leaving. It is bounded: you consented to the pairing in the first place, and they are sitting in the same cooldown you are, so they cannot do it to you twice in a row. It is deliberate — cooling both sides is what stops wallets churning through partners to keep re-triggering the discount. It is worth knowing before you pair with a stranger.

What unpairing does not do: it does not touch entitlement you have already earned, and it does not touch anything sitting in the escrow. Those stay yours, claimable, paired or not. Unpairing only stops the meter running.

Who counts as “you”

05
Know this too

Smart accounts and 4337 users are read as their bundler.

When a swap arrives through a router, the pool hands the hook the router’s address, not the trader’s. Uniswap v4 gives a hook no other handle on the person behind the trade, so $BUDS resolves the trader with tx.origin — the account that signed the transaction.

For an ordinary wallet that is exactly right. For a smart-contract wallet or an ERC-4337 user operation it is not: the signer of the transaction is the bundler or the relayer, so that is who the hook sees. Those users pay the standard rate and book no entitlement, even when their account is properly paired.

The inverse holds too — if a paired EOA relays somebody else’s trade, the discount applies and that EOA’s pair earns the entitlement.

Nothing else in the system depends on tx.origin: the registry, the escrow and the claim path are all plain address logic and work correctly for any kind of account. Only the per-swap discount and the entitlement booking are affected. Fixing it properly needs a signed-intent path through the hook’s swap data, which is a design change rather than a patch, and it is not in this version. If you use a smart account: trade $BUDS from an EOA, or accept that you are one of the people funding the pairs.

Every call you would ever make

06
proposeBuddy(other)

Offer to pair with one named wallet. Replaces any offer you had outstanding. Binds nothing until it is accepted.

withdrawProposal()

Take your outstanding offer back off the table.

acceptBuddy(proposer)

Take an offer that names you. This is the only call that forms a pair, and it needs the proposal already standing on the other side.

unpair()

Dissolve the pair. One side is enough. Puts both wallets into the pairing cooldown; leaves earned entitlement and escrow untouched.

claim()

Pull your escrowed $BUDS. Yours whether you are currently paired or not, and whenever you want it.

splitPot()

Spend the pot on a market buy of $BUDS and push it into the escrow. Anyone may call it; the caller keeps a small tip. Subject to a cooldown, a per-call ETH cap and a slippage floor.

feedPot()

Send ETH into the pot from anywhere, on purpose. It is shared out on the next split exactly like collected fees.

buddy(wallet) · feeFor(wallet)

Read-only. Who a wallet is currently paired with, and the rate that wallet would pay on a buy right now.

Status

07

None of this is deployed. There is no contract address, no pool, no liquidity and nothing to buy, and none of the rates, caps or cooldowns described above have been chosen yet — they are constructor arguments and they will be published here before the pool opens.

The contracts carry 108 passing tests, including stateful invariants asserting that the pairing graph is always a valid one-to-one matching, that a cooling wallet is never paired, that the escrow stays solvent, and that the entitlement book always adds up. That is work by the people who wrote it. There has been no independent external audit.

Back to the idea ←