Omniscia Olympus DAO Audit
BondDepository Manual Review Findings
BondDepository Manual Review Findings
BDY-01M: Improper Bond Price Assumption
Type | Severity | Location |
---|---|---|
Logical Fault | Major | BondDepository.sol:L328-L341 |
Description:
The _bondPrice
adjusts the on-chain minimum price of a bond to 0
if the price of the bond is exceeded, however, the debtRatio
variable relies on the total supply of OHM which is fully manipulateable and thus can cause the price of a bond to increase above the minimum temporarily by taking advantage of the debtRatio
reliance on OHM.totalSupply
.
Example:
328/**329 * @notice calculate current bond price and remove floor if above330 * @param _BID uint331 * @return price_ uint332 */333function _bondPrice(uint256 _BID) internal returns (uint256 price_) {334 Bond memory info = bonds[_BID];335 price_ = info.terms.controlVariable.mul(debtRatio(_BID)).add(1000000000).div(1e7);336 if (price_ < info.terms.minimumPrice) {337 price_ = info.terms.minimumPrice;338 } else if (info.terms.minimumPrice != 0) {339 bonds[_BID].terms.minimumPrice = 0;340 }341}342
343/**344 * @notice converts bond price to DAI value345 * @param _BID uint346 * @return price_ uint347 */348function bondPriceInUSD(uint256 _BID) public view returns (uint256 price_) {349 Bond memory bond = bonds[_BID];350 if (address(bond.calculator) != address(0)) {351 price_ = bondPrice(_BID).mul(bond.calculator.markdown(address(bond.principal))).div(100);352 } else {353 price_ = bondPrice(_BID).mul(10**IERC20Metadata(address(bond.principal)).decimals()).div(100);354 }355}356
357// DEBT358
359/**360 * @notice calculate current ratio of debt to OHM supply361 * @param _BID uint362 * @return debtRatio_ uint363 */364function debtRatio(uint256 _BID) public view returns (uint256 debtRatio_) {365 debtRatio_ = FixedPoint.fraction(currentDebt(_BID).mul(1e9), OHM.totalSupply()).decode112with18().div(1e18);366}
Recommendation:
We advise the function to not adjust the minimum price as it can lead to the pricing of a bond becoming less-than-minimum under the right circumstances.
Alleviation:
The Olympus DAO team considered this exhibit but decided to retain the current behaviour of the code in place.
BDY-02M: Inexistent Validation of Terms
Type | Severity | Location |
---|---|---|
Input Sanitization | Medium | BondDepository.sol:L97-L129 |
Description:
All arguments of the setTerms
function are not sanitized and as such can be arbitrarily set to values that may be illogical or result in exploits, such as a conclusion
that is beyond the expiration
of the bond and other similar issues.
Example:
97/**98 * @notice set minimum price for new bond99 * @param _id uint100 * @param _controlVariable uint101 * @param _fixedTerm bool102 * @param _vestingTerm uint103 * @param _expiration uint104 * @param _conclusion uint105 * @param _minimumPrice uint106 * @param _maxPayout uint107 * @param _maxDebt uint108 * @param _initialDebt uint109 */110function setTerms(111 uint256 _id,112 uint256 _controlVariable,113 bool _fixedTerm,114 uint256 _vestingTerm,115 uint256 _expiration,116 uint256 _conclusion,117 uint256 _minimumPrice,118 uint256 _maxPayout,119 uint256 _maxDebt,120 uint256 _initialDebt121) external onlyGuardian {122 require(!bonds[_id].termsSet, "Already set");123
124 Terms memory terms = Terms({controlVariable: _controlVariable, fixedTerm: _fixedTerm, vestingTerm: _vestingTerm, expiration: _expiration, conclusion: _conclusion, minimumPrice: _minimumPrice, maxPayout: _maxPayout, maxDebt: _maxDebt});125
126 bonds[_id].terms = terms;127 bonds[_id].totalDebt = _initialDebt;128 bonds[_id].termsSet = true;129}
Recommendation:
We strongly recommend some form of input sanitization to be enforced on the bond terms as in the current state the guardian has significant control over the protocol's normal operation.
Alleviation:
The Olympus DAO team considered this exhibit but decided to retain the current behaviour of the code in place.
BDY-03M: Inexplicable Optional Value of Decay
Type | Severity | Location |
---|---|---|
Logical Fault | Medium | BondDepository.sol:L390-L402 |
Description:
The debtDecay
function relies on the vestingTerm
variable of the Term
struct which is meant to be an optional variable based on the documentation of the struct.
Example:
390/**391 * @notice amount to decay total debt by392 * @param _BID uint393 * @return decay_ uint394 */395function debtDecay(uint256 _BID) public view returns (uint256 decay_) {396 Bond memory bond = bonds[_BID];397 uint256 blocksSinceLast = block.number.sub(bond.lastDecay);398 decay_ = bond.totalDebt.mul(blocksSinceLast).div(bond.terms.vestingTerm);399 if (decay_ > bond.totalDebt) {400 decay_ = bond.totalDebt;401 }402}
Recommendation:
We advise its purpose to be better defined in the struct declaration as bonds without a fixed term are possible, causing decay to misbehave.
Alleviation:
The Olympus DAO team considered this exhibit but decided to retain the current behaviour of the code in place.