RMM-01 Math Approximation Error
A user was able to swap 0.05 ETH into 1700 USDC every 30 minutes as the pool approached maturity, starting at a specific window before expiry. In total, approximately 34,000 in mispriced USDC was extracted from the pool over the course of 10 hours, the vast majority of which was Primitive controlled liquidity.
In an immediate response, the Primitive team followed its Incident Response Plan by disabling Add Liquidity and Create Pool functionality in the RMM Interface hosted at app.primitive.xyz. Liquidity Removal functionality is not impacted, and we recommend all users remove 100% of their liquidity from any outstanding RMM-01 positions.
The source of this error is well understood by our team. In preparation for the release of Primitive's new AMM protocol, we authored a completely new math library which, from our internal testing, completely removes the source of this error. RMM-01 would be safe in all conditions if redeployed with this revised math library.
DeFi security is a challenging and continuous process. Primitive is committed to expanding our active security measures by consistently re-evaluating the security of our products and protocols.
We will release a follow-up blog post outlining the future of the RMM-01 protocol, planned releases, and what to expect from the Primitive team in the coming months.
Timeline of Events
September 08, 2022
06:35 UTC - First bad trade occurs, $1600 at risk per 30 minutes.
13:36 UTC - Primitive team notified via Immunefi bug report.
17:00 UTC - Known Primitive LPs liquidity removed. <$2000 in total at risk.
17:15 UTC - Primitive App at app.primitive.xyz updated to disable adding liquidity to pools.
17:32 UTC - Greyhat user who submitted and profited from the bad trades contacted.
23:59 UTC - Pool 0x1803a83d9cefaff28728173c501258b5c0c61dc3acac20302a52bbc43e174e58 expired, $0 at risk.<!-- | Time | Event | |------|-------| |06:35 UTC|First bad trade occurs, \$1600 at risk per 30 minutes. || 13:36 UTC | Primitive team notified via Immunefi bug report. | | 17:00 UTC | Known Primitive LPs liquidity removed. <\$2000 in total at risk. | | 17:15 UTC | Primitive App at app.primitive.xyz updated to disable adding liquidity to pools. | |17:32 UTC|Greyhat user who submitted and profited from the bad trades contacted.| |23:59 UTC|Pool 0x1803a83d9cefaff28728173c501258b5c0c61dc3acac20302a52bbc43e174e58 expired, \$0 at risk.| -->
The RMM protocol is a Constant Function Market Maker that uses a trading rule which takes advantage of transcendental math functions. These functions must be approximated via algebraic operations in order to use them in the RMM protocol smart contracts.
The specific line of code in question can be found here. The implementation of the cumulative distribution function approximation component on this line is found here. One of the parameters used in this function is the time to pool expiry, denominated in seconds. For pools with a small amount of time to expiry (less than 65810 seconds) and a reported price greater or equal to the strike price, the error of the cumulative distribution function approximation when compared to the actual output of the respective transcendental function introduces a pricing discrepancy.
The Primitive team discussed this approximation error with Trail of Bits during its 8-week audit in January, 2022. At the time, we recognized the significance of the error, but after extensive testing, we did not find a way to use it to take advantage of the pool's underlying pricing mechanism. The codebase was covered by multiple audit teams who reviewed the protocol over 20 audit weeks. There have been no code changes since the final audit, making RMM-01 protocol one of the most audited protocols to exist. Although the audits were extensive, testing and fuzzing did not cover the alignment of specific time-based conditions that caused the aforementioned pricing discrepancy.