Omniscia Platypus Finance Audit
Core Manual Review Findings
Core Manual Review Findings
COR-01M: Equilibrium Point Arbitrage
Type | Severity | Location |
---|---|---|
Mathematical Operations | Medium | Core.sol:L148-L150, L201-L204 |
Description:
The system combats arbitrage opportunities by enforcing a dynamic withdrawal and deposit fee that scales with the cash and liability held by the system. However, it manages the case of equilibrium by not applying a fee in either deposits or withdrawals.
Example:
125/**126 * @notice Yellow Paper Def. 6.2 (Withdrawal Fee)127 * @dev When covBefore >= 1, fee is 0128 * @dev When covBefore < 1, we apply a fee to prevent withdrawal arbitrage129 * @param k K slippage parameter in WAD130 * @param n N slippage parameter131 * @param c1 C1 slippage parameter in WAD132 * @param xThreshold xThreshold slippage parameter in WAD133 * @param cash cash position of asset in WAD134 * @param liability liability position of asset in WAD135 * @param amount amount to be withdrawn in WAD136 * @return The final fee to be applied137 */138function _withdrawalFee(139 uint256 k,140 uint256 n,141 uint256 c1,142 uint256 xThreshold,143 uint256 cash,144 uint256 liability,145 uint256 amount146) internal pure returns (uint256) {147 uint256 covBefore = cash.wdiv(liability);148 if (covBefore >= WAD) {149 return 0;150 }151
152 if (liability <= amount) {153 return 0;154 }155
156 uint256 cashAfter;157 // Cover case where cash <= amount158 if (cash > amount) {159 cashAfter = cash - amount;160 } else {161 cashAfter = 0;162 }163
164 uint256 covAfter = (cashAfter).wdiv(liability - amount);165 uint256 slippageBefore = _slippageFunc(k, n, c1, xThreshold, covBefore);166 uint256 slippageAfter = _slippageFunc(k, n, c1, xThreshold, covAfter);167 uint256 slippageNeutral = _slippageFunc(k, n, c1, xThreshold, WAD); // slippage on cov = 1168
169 // fee = [(Li - Di) * SlippageAfter] + [g(1) * Di] - [Li * SlippageBefore]170 return171 ((liability - amount).wmul(slippageAfter) + slippageNeutral.wmul(amount)) - liability.wmul(slippageBefore);172}173
174/**175 * @notice Yellow Paper Def. 7.2 (Deposit Fee)176 * @dev When covBefore <= 1, fee is 0177 * @dev When covBefore > 1, we apply a fee to prevent deposit arbitrage178 * @param k K slippage parameter in WAD179 * @param n N slippage parameter180 * @param c1 C1 slippage parameter in WAD181 * @param xThreshold xThreshold slippage parameter in WAD182 * @param cash cash position of asset in WAD183 * @param liability liability position of asset in WAD184 * @param amount amount to be deposited in WAD185 * @return The final fee to be applied186 */187function _depositFee(188 uint256 k,189 uint256 n,190 uint256 c1,191 uint256 xThreshold,192 uint256 cash,193 uint256 liability,194 uint256 amount195) internal pure returns (uint256) {196 // cover case where the asset has no liquidity yet197 if (liability == 0) {198 return 0;199 }200
201 uint256 covBefore = cash.wdiv(liability);202 if (covBefore <= WAD) {203 return 0;204 }205
206 uint256 covAfter = (cash + amount).wdiv(liability + amount);207 uint256 slippageBefore = _slippageFunc(k, n, c1, xThreshold, covBefore);208 uint256 slippageAfter = _slippageFunc(k, n, c1, xThreshold, covAfter);209
210 // (Li + Di) * g(cov_after) - Li * g(cov_before)211 return ((liability + amount).wmul(slippageAfter)) - (liability.wmul(slippageBefore));212}
Recommendation:
We advise this point of the formulas to be evaluated as it may open up multi-step attack vectors where attackers bring the system state from a negative (< 1
) cash-to-liability state to equilibrium (= 1
) and then to a positive (> 1
) cash-to-liability state instead of directly transitioning from a negative to a positive state. To achieve this, we advise the Platypus team to introduce corresponding test suites validating the mathematical model in such a scenario.
Alleviation:
The Platypus team has provided us with two articles analyzing a potential withdrawal arbitrage attack vector and justifying why the withdrawal fee imposed by the system counteracts such attacks. After consideration, we ascertained that the articles provided in correlation with the codebase adequately deal with the exhibit.
COR-02M: Potential Nullification of k
Type | Severity | Location |
---|---|---|
Mathematical Operations | Minor | Core.sol:L43 |
Description:
For relatively small values of x
the rpow
instruction may not yield a sufficiently large value to be properly casted to the WAD
precision, especially if the rpow
instruction is performed with a large power and a fractional number.
Example:
23/**24 * @notice Yellow Paper Def. 2.4 (Price Slippage Curve)25 * @dev Calculates g(xr,i) or g(xr,j). This function always returns >= 026 * @param k K slippage parameter in WAD27 * @param n N slippage parameter28 * @param c1 C1 slippage parameter in WAD29 * @param xThreshold xThreshold slippage parameter in WAD30 * @param x coverage ratio of asset in WAD31 * @return The result of price slippage curve32 */33function _slippageFunc(34 uint256 k,35 uint256 n,36 uint256 c1,37 uint256 xThreshold,38 uint256 x39) internal pure returns (uint256) {40 if (x < xThreshold) {41 return c1 - x;42 } else {43 return k.wdiv((((x * RAY) / WAD).rpow(n) * WAD) / RAY); // k / (x ** n)44 }45}
Recommendation:
We advise the formulas to be evaluated as to whether such a condition is expected to be encountered under normal operations and a potentially default value to be returned, such as slippage equivalent to 100% / 0% rather than a fatal failure.
Alleviation:
The Platypus team has provided us with sufficient test coverage validating small values of x
and thus ensuring that the formula preforms as expected in real-world scenario. In light of this, we consider this exhibit dealt with.