JoinMarket Analyzer: Understanding CoinJoin Change OutputsJoinMarket Analyzer: Understanding CoinJoin Change Outputs
I've released a tool called joinmarket-analyzer to match inputs and change outputs in JoinMarket transactions, identifying who the taker was.
Goal: The purpose is not to spread FUD, but to raise awareness. It's crucial to understand that this analysis only affects change outputs. The equal-amount outputs—which provide the actual privacy in a CoinJoin—remain indistinguishable.
The tool uses Integer Linear Programming (ILP) to match inputs with their respective changes and determine which participant is the likely "Taker" (the one initiating the transaction and paying fees) and which are the "Makers" (liquidity providers earning fees).
Example UsageExample Usage
You can run it easily with Docker:
docker run --rm ghcr.io/m0wer/joinmarket_analyzer:master \
0cb4870cf2dfa3877851088c673d163ae3c20ebcd6505c0be964d8fbcc856bbf \
--max-fee-rel 0.001 --max-solutions 1ResultsResults
The tool outputs the probable structure of the transaction:
...
Taker: Participant 4 (pays 21,368 sats)
💰 Participant 1 (maker)
Inputs: [0]
Outputs: Equal=6.3M sats, Change=113M sats
Fee receives: 458 sats
...
🎯 Participant 4 (taker)
Inputs: [4]
Outputs: Equal=6.3M sats, No change output
Fee pays: 21,368 sats
...View this transaction on mempool.space
Future PossibilitiesFuture Possibilities
This tool lays the groundwork for more advanced privacy research:
- Entropy Evaluation: Measure how "ambiguous" change outputs are. If multiple valid solutions exist, the Taker is harder to pinpoint.
- Algorithm Design: Evaluate and improve taker algorithms to intentionally create ambiguous change structures.
- Market Stats: Analyze historical CoinJoins to gather statistics on fee limits used by takers and earnings by makers.
Check out the code and contribute: https://github.com/m0wer/joinmarket-analyzer
Why does it matter that the taker is known? The next round is not necessarily the same taker.
Maybe it doesn't. But here are some cases where it does:
And I'm sure there might be other reasons depending on the case. The project is just a tool to do the matching.
I'm pretty sure in the docs they say that 1 round is not sufficiently conjoined.
Anyway, you're probably right that some people won't understand and are going to mess it up.
Yes, and it also says that the protocol is designed for privacy of the equal outputs, not the change. And that change should not be spent together with equal outputs.
I actually just wanted a way to analyze transactions to gather stats on the fee limits used and optimize maker offers.
The other idea is to find ways to make change outputs ambiguous on purpose so that they gain some privacy as well and economize the coinjoin a bit more.
And normally it will not be, as equal output and change will end up in different mixdepths.
In Jam the change is always separated from the CJ output.
Negative offers might be the way.
I saw Floppy comment the other day on Joinstr about the change being submarine swapped into the LN channel.
Optimize maker offers in terms of maximizing profits, not in number of rounds.
Change can also be mixed in coinjoins. There's actually a setting for consolidating change as a maker by providing multiple inputs. The alternative is of course the submarine swaps yes, but usually pretty expensive.
A submarine swap would be cheaper than paying for a number of CJ participants. The TX fee is already for too.
Depends on the size, but most times yes.
But I meant as a maker, where a taker pays the extra transaction fees from the additional inputs. So you get the consolidation for free (or even making some profits), you help the taker disguise their inputs, and you get a proper equal output.
Because if you pay someone using a JM tx (which is the goal when acting as a taker) the receiver can easily know your change output, which is not good.
JM provides good forward privacy but in some case really bad backward privacy IMO
And if a taker gains no backward privacy, why would he even use the tool to spend in the first place ? Which lead to incentive problem because if there is no taker there is no Coinjoin anymore.
Very good answer.
Argh the link is wrong in the post content, should be https://github.com/m0wer/joinmarket_analyzer