Summary
INKR is a Uniswap v4 hook. Before a pool that adopts it quotes a swap, it resolves the trader’s ERC-8004 identity, reads a score attached to that identity, and picks the fee the pool declared for that answer.
Higher reputation, better conditions. No identity, standard conditions. A pool that wants to may also refuse below a floor, which is a different thing from pricing and is treated as one.
The identity problem
v4 hands a hook the address that called the PoolManager. For any real trade that is a router, not the agent. A hook that graded that address would give every agent behind a given router the same tier and would appear to work perfectly while doing so. This is the single thing that makes the problem harder than it sounds.
How an agent is resolved
The declared path is checked, not trusted: an agent id anybody could assert would be a fee discount anybody could take. A test drives exactly that attack — a stranger putting a trusted agent’s id in hookData — and it is quoted the unknown rate.
The direct path uses tx.origin. That is a payout-free identification, not an authorisation, so the usual objection does not apply. The real limitation is stated plainly: under ERC-4337 the sender is the bundler, so a smart-account agent must use the declared path. That path exists precisely because the direct one cannot serve everybody.
The pool policy
Whoever registers a pool writes its policy once, and it is then immutable — by them, by INKR, by anybody.
Registration validates the ordering: trustedFee ≤ baseFee ≤ unknownFee. A policy that quoted a trusted agent worse than a stranger would be a reputation system that punishes reputation, so it is refused at registration rather than left to be discovered by whoever trades into it.
Registration is open to anyone and costs nothing. There is no allowlist to be on, because a gate on the gate is an admin with extra steps.
The gate
minScore is the only thing in INKR that can stop a trade. When it is zero, which is the default, the pool declines nobody and reputation only ever changes the price. When a pool sets it, a swap below the floor reverts with ReputationTooLow naming the agent, the score and the requirement — so the refusal is legible rather than a silent failure.
Where the score comes from
ERC-8004 standardises who may leave feedback, not a number out of a hundred. There is no score() in the ERC and INKR does not pretend there is. Turning feedback into one number is an opinion, so that opinion lives in a separate contract behind IReputationSource, which the hook takes as a constructor argument. Disagree with the model and you deploy a different scorer; you do not need a new hook.
The reference scorer, stated so it can be argued with:
- Only registered agents may rate. A rating from an address with no identity is free to produce, and anything free is produced infinitely.
- One live rating per rater per subject. Re-rating replaces; it does not accumulate. Otherwise the loudest counterparty is the reputation.
- Nobody rates themselves.
- The score is a plain mean and the sample count travels with it. Not a weighting nobody can reproduce. Consumers discount thin records themselves, and the hook does exactly that via
minSamples.
When the registry misbehaves
A pool whose fee depends on an external contract must survive that contract misbehaving, or the external contract is really a pause button somebody else owns.
Every registry call is a staticcall with a 120,000 gas ceiling, and any failure resolves to unknown rather than reverting. A test points the hook at a registry that reverts, then at one that burns gas in an infinite loop, then at one that returns garbage, and swaps succeed through all three.
What the hook cannot do
The hook address carries BEFORE_INITIALIZE and BEFORE_SWAP only. The absences are the guarantee:
- No liquidity permissions. It is never called on an add or a remove, so it can never trap a position and a provider can always leave.
- No return-delta bits. It cannot take a cut of a trade or alter its amounts. It names a fee, or it declines.
- No global admin, no owner, no upgrade path. Nothing INKR holds can raise your fee after you have read the policy.
beforeInitialize refuses any pool that is not a dynamic-fee pool. On a static-fee pool the override would be ignored and the whole protocol would be a no-op nobody notices, which is worse than a revert everybody sees.
Addresses
23/23 tests, all against the real Robinhood Chain PoolManager on a fork. Not deployed yet — addresses appear on the agents page the moment they exist, and nowhere earlier. No third-party audit.
What it does not claim
- An identity proves nothing on its own. Anybody can register, exactly as anybody can buy a domain. The identity is the handle; the reputation is the judgement.
- Sybils are not impossible. Requiring raters to hold identities makes a ring cost one registration each and leaves it visible on chain. That is a cost, not a barrier, and anyone relying on the score should price it that way.
- A score is only as good as its source. The reference scorer is a mean of ratings from registered agents. It is deliberately simple and deliberately replaceable.
- Smart accounts must declare. Under ERC-4337 the direct path resolves the bundler, not the agent.
- Not audited. Nothing here is a promise of anything.