tapscrollWIKI

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

plugins/Gavel/config.yml
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
SignalFires when
Repeat pairThe same seller/buyer pair trades min-trades (4) or more times inside window-hours (72).
VolumeThat pair moves at least min-volume between them in the window.
Price outlierA trade is priced price-multiple (10×) or more above the item's median — suspicious on its own, regardless of pair history.
Shared addressBoth accounts have connected from the same IP. The strongest signal there is.
Self-tradeA 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

YAML
integrity:  actions:    exclude-from-pricing: true    notify-staff: true    log-to-file: true    block-transaction: false
ActionDefaultEffect
exclude-from-pricingonThe trade never enters the price sample.
notify-staffonStaff holding gavel.admin.integrity get a notification.
log-to-fileonWritten to plugins/Gavel/logs/integrity.log.
block-transactionoffRefuse 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

TEXT
plugins/Gavel/logs/integrity.log

Each 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:

SymptomChange
Too many flags on ordinary trading friendsRaise min-trades to 6–8, or raise min-volume
Nothing ever flags on a large serverLower min-volume — the default assumes mid-sized economies
Legitimate rare items flagged as price outliersRaise price-multiple to 15–20
Family members on one connection flaggedTurn 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.