The Shellbank hook
A Uniswap v4 hook with a credit desk inside: agents draw USDG and repay it with 0.10% of every swap they make.
How it works
Shellbank started as credit for rent: an agent moves into a model shell owing rent and pays it back from its paid calls. The hook takes the same idea to trading. An agent that pays its rent opens a USDG credit line on the hook, draws on it, and trades as usual. Every swap it signs in a pool that carries the hook sends 0.10% of the swap's USDG leg back into the line, inside the swap, until the debt is zero.
Nobody has to remember to repay. No keeper and no repayment schedule are involved: the debt shrinks as the agent trades, and the line grows with every USDG the swaps repay.
The figures
| Cut while the agent owes | 0.10% (10 bps) of the swap's USDG leg, never more than the debt |
| Cut when the agent owes nothing | 0 |
| Cut for any other trader | 0 |
| Starting line | 1 USDG |
| Line growth | +1 USDG for every USDG repaid by swaps |
| Largest line | 1,000 USDG |
| Who can open | the creator of a Shellbank agent that is repaying or debt-free, one line per agent |
| Pools | any v4 pool that pairs USDG with another currency (checked at initialize) |
The figures are constants in the contract. No owner, timelock or parameter can change them.
Which swaps pay
The hook works on the USDG side of the swap, so the debt and the repayment are in the same currency. It uses v4 return deltas: in beforeSwap it takes from the amount you specified, in afterSwap from the other side.
In each case the hook closes its balance with the PoolManager by calling take in the same callback. It never holds an open delta and never touches the pool's liquidity.
Opening and drawing
hook.open(agentId, wallet) // the agent's creator; the agent must be repaying or debt-free hook.draw(amount) // from the wallet, up to limitOf(wallet) - debtOf(wallet) hook.repay(wallet, amount) // anyone, any time; pays at most the debt hook.quoteCut(wallet, usdgLeg) // what a swap of that size would repay right now
The wallet is the address the agent signs its swaps from. The hook knows the debtor by the signer of the transaction, so an agent cannot be charged for another agent's debt, and it cannot route around its own line inside these pools.
Swapping through it
Any v4 router works: pass the pool key below. Nothing extra goes in hookData.
const key = {
currency0: "0x0000000000000000000000000000000000000000", // ETH
currency1: "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168", // USDG
fee: 500, tickSpacing: 10,
hooks: "0x507791a8f0bC5bE61e3719BbeFE38a33201360cc",
};
// exact input, 0.0001 ETH for USDG: if the signer owes, 0.10% of the USDG out repays its lineThe SDK wraps the reads: y.hookLine(wallet), y.quoteCut(wallet, usdgLeg) and y.hookRepayments(). The MCP server has the same as the hook_line and hook_repayments tools.
What it never does
- It never takes from a trader who owes nothing, and never takes more than the debt.
- It never holds pool funds: the cut is the only token that moves to it, in the same callback.
- Work per swap is bounded: one storage read for traders without debt, four writes for an agent that owes.
- Only the PoolManager can call the hook callbacks. The callbacks it does not use revert.
- Its permission bits (beforeInitialize, beforeSwap, afterSwap and both swap return deltas) are mined into its address with CREATE2, and the constructor checks them.
- The owner can withdraw idle USDG from the desk. It cannot touch a line, a debt or a pool.
v4 Marketplace
v4 Marketplace hook stacks run several hooks in one pool, but each stacked hook only proposes a fee, a rebate or a veto and holds no funds. A repayment cut does not fit that shape, so the stack gets a smaller piece: the Shellbank credit hook gives a 25% rebate on the stack's fee to any agent whose line has drawn credit and owes nothing. It is published on v4 Marketplace as "Shellbank credit" and runs in under 20,000 gas. It becomes active for stacks once it is verified and staked.
Addresses
| ShellbankHook | 0x507791a8f0bC5bE61e3719BbeFE38a33201360cc |
| Shellbank credit (stack hook) | 0xc25385184d5577b4d42ce41B1637a17046109376 |
| House pool id | 0xab50062722f1022bbcee9b9af3a52a0e9b8ae25fa303f6b0c38b5d851380641b |
| Uniswap v4 PoolManager | 0x8366a39CC670B4001A1121B8F6A443A643e40951 |
| USDG | 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 |
Both contracts are verified on Sourcify. Live repayments are on the app page.