Skip to content

How Boon routes USDC depending on whether a handle has linked a wallet.

Boon.tip() has one sender action and two recipient outcomes.

Sender wallet
│ approve(BoonContract, amount) if needed
│ Boon.tip(handleHash, displayHandle, amount, note)
┌──────────────────────────────────────────────────────────┐
│ Boon.sol on Base │
│ ─ always emit Tip (intent event, indexed by subgraph) │
│ │
│ ┌── linkedWallet[handleHash] == 0x0 ? │
│ │ │ yes → escrow[handleHash] += amount │
│ │ │ (recipient claims later, no expiry) │
│ │ │ │
│ │ └ no → transfer USDC to linked wallet │
│ │ → emit Pushed │
│ └───────────────────────────────────────────────────── │
└──────────────────────────────────────────────────────────┘
Subgraph: Tip status = ESCROWED or PUSHED
  1. The sender transfers USDC into the Boon contract.
  2. The contract emits Tip.
  3. The amount is added to escrow[handleHash].
  4. The recipient can later prove the handle and claim.

Escrow does not expire. The sender cannot recall it.

  1. The sender transfers USDC into the Boon contract.
  2. The contract emits Tip.
  3. The contract transfers USDC to the linked wallet.
  4. The contract emits Pushed.

Future boons to the same handle push automatically after the first successful link.

After a handle is linked, anyone can call claim(handleHash). The contract sends escrow only to linkedWallet[handleHash], never to the caller unless the caller is also the linked wallet.

A normal link() can bind a handle with no existing escrow. A pre-funded handle uses linkEscrowed() and requires both the trusted OAuth signer and escrow guardian to sign the same Link digest. That reduces the blast radius of a single signer leak for already-escrowed value.