Market integrity
Wash-trading, alt-account and self-trade detection — and why flagged trades are excluded from pricing rather than blocked.
Gavel v1.0.0Paper · Folia supported1.21 – 1.21.x
An auction house is a money-laundering machine unless somebody is watching. Two accounts trading the same item back and forth at inflated prices moves currency between players with no paper trail and, as a side effect, poisons every price estimate on the server.
Gavel scores trades for exactly that.
What gets flagged
integrity: enabled: true wash-trading: enabled: true window-hours: 72 min-trades: 4 min-volume: 500000.0 price-multiple: 10.0 shared-address-check: true self-trade-check: true| Signal | Fires when |
|---|---|
| Repeat pair | The same seller/buyer pair trades min-trades (4) or more times inside window-hours (72). |
| Volume | That pair moves at least min-volume between them in the window. |
| Price outlier | A trade is priced price-multiple (10×) or more above the item's median — suspicious on its own, regardless of pair history. |
| Shared address | Both accounts have connected from the same IP. The strongest signal there is. |
| Self-trade | A player buys their own listing through an alt. |
The three wash-trading signals compound: a pair that trades often and at ten times the median is far past the threshold that either alone would set.
What happens to a flagged trade
integrity: actions: exclude-from-pricing: true notify-staff: true log-to-file: true block-transaction: false| Action | Default | Effect |
|---|---|---|
exclude-from-pricing | on | The trade never enters the price sample. |
notify-staff | on | Staff holding gavel.admin.integrity get a notification. |
log-to-file | on | Written to plugins/Gavel/logs/integrity.log. |
block-transaction | off | Refuse the trade outright. |
Blocking is off for a reason
A false positive that blocks a legitimate trade costs you a support ticket, an angry player and a reputation for a broken auction house. A false positive that only excludes one sale from a 30-day statistical sample costs nothing at all.
Leave block-transaction: false unless you have watched your own integrity log for a few weeks and
know what your false-positive rate looks like.
Why exclusion is the real defence
exclude-from-pricing is the setting that matters, and it works even when nobody reads the log.
The reason to manipulate a market is to move the reference price — pump an item's median, then sell your stock to real players at the inflated "fair" price the plugin is now advertising. If the manipulated trades never enter the sample, the entire scheme produces nothing but two accounts passing money in a circle.
That is why integrity and pricing share infrastructure rather than being separate features. The detector exists to protect the estimator.
Reading the log
plugins/Gavel/logs/integrity.logEach line records the trade, both accounts, the item, the price, the signals that fired and what was done. It is plain text and safe to grep.
Realistic patterns you will see:
- Two accounts, same IP, trading dirt at 500,000. Currency transfer between a player's own accounts, or an off-server sale being settled. Worth a look.
- A trade at 40× the median, once, between accounts with no history. Usually a fat-fingered price and an opportunistic buyer, not abuse.
- A pair trading eight times in a day at normal prices. Usually two friends running a shop arrangement. Noise, unless the volume is also extreme.
Tuning
Start with the defaults and watch for two weeks. Then:
| Symptom | Change |
|---|---|
| Too many flags on ordinary trading friends | Raise min-trades to 6–8, or raise min-volume |
| Nothing ever flags on a large server | Lower min-volume — the default assumes mid-sized economies |
| Legitimate rare items flagged as price outliers | Raise price-multiple to 15–20 |
| Family members on one connection flagged | Turn off shared-address-check |
Shared IPs are not proof
Siblings, dorms and shared networks exist. shared-address-check is a strong signal, not a
conviction — which is exactly why the default response is to exclude the trade from statistics
rather than to punish anybody.
Privacy note
The shared-address check compares connection addresses that your server already records. Nothing is sent anywhere; the comparison happens in your own database. If you operate in the EU and publish a privacy policy, this is worth naming under your existing server-log entry.