###### tags: `Final Report` Fountain Protocol Incremental Audit (FPIA-1) === > Copyright © 2022 by Verilog Solutions. All rights reserved. > April 12, 2022 > by **Verilog Solutions** <!-- <span style="position:fixed; top:200px; right:400px; opacity:0.5; font-size: 20px; z-index:99;">watermark</span> --> ![Fountain-COVER](https://hackmd.io/_uploads/HJhSKh_m5.png) This report presents Verilog Solutions's incremental smart contract auditing engagement with Fountain Protocol, especially for its `LPOracleAnchoredView.sol` smart contract. Fountain Protocol is one of the first Lending protocols on the Emerald Paratime of Oasis Network. --- ## Table of Content [TOC] --- ## Summary of the Incremental Audit We audited Fountain Protocol and the previous auditing report is [here](https://hackmd.io/C_lPwlT0TsuONfUWkQzfpw) with hash [cc16318c2db70fdc8fbfb52c26c1f7b9d15875f8](https://github.com/dev-fountain/fountain-protocol/tree/cc16318c2db70fdc8fbfb52c26c1f7b9d15875f8). This is the incremental audit for file [`LPOracleAnchoredView.sol`](https://github.com/dev-fountain/fountain-protocol/blob/e2c39e77c4df4a93f807abdd546a40ff76a7b483/contracts/LPOracleAnchoredView.sol). The main functionality added is the calculation for LP token price. ## Privileged Roles 1. The caller of the `constructor` (*i.e.*, the deployer of the smart contract) has the privileged role to select the token pairs and passing the tokens' symbols and addresses to the function. ```solidity= constructor(address _ref,OracleTokenConfig[] memory configs) public { ref = IStdReference(_ref); for(uint i = 0; i < configs.length; i++){ OracleTokenConfig memory config = configs[i]; require(config.baseUnit > 0, "baseUnit must be greater than zero"); CTokenConfigs[config.symbol] = config; cTokenSymbol[config.cToken] = config.symbol; } } ## Findings & Improvement Suggestions #### <html></html> <style> .info { background-color:mediumseagreen; font-size: 12px; color: white; border-radius:4px; padding: 1px 4px; font-weight: 500; display: inline-block; margin: 2px; letter-spacing: 0.3px} </style><style> .minor { background-color: #698999; font-size: 12px; color: white; border-radius:4px; padding: 1px 4px; font-weight: 500; display: inline-block; margin: 2px; letter-spacing: 0.3px} </style><style> .medium { background-color: #FFCA0F; color: #121212; font-size: 12px; border-radius:4px; padding: 1px 4px; font-weight: 500; display: inline-block; margin: 2px; letter-spacing: 0.3px} </style><style> .major{ background-color: #FF6B4A; color: white; font-size: 12px; border-radius:4px; padding: 1px 4px; font-weight: 500; display: inline-block; margin: 2px; letter-spacing: 0.3px} </style><style> .critical{ background-color: #FF0000; color: white; font-size: 12px; border-radius:4px; padding: 1px 4px; font-weight: 500; display: inline-block; margin: 2px; letter-spacing: 0.3px} </style> <span class='info'>Informational</span><span class='minor'>Minor</span><span class='medium'>Medium</span><span class='major'>Major</span><span class='critical'>Critical</span> | | Total | Acknowledged | Resolved | | ------------- | ----- | ------------ | -------- | | Critical | 0 | 0 | 0 | | Major | 1 | 1 | 1 | | Medium | 0 | 0 | 0 | | Minor | 0 | 0 | 0 | | Informational | 3 | 3 | 3 | ### Critical none ;) ### Major 1. The token decimal alignment is not needed in function [`reserveProductAndTotalSupply()`](https://github.com/dev-fountain/fountain-protocol/blob/e2c39e77c4df4a93f807abdd546a40ff76a7b483/contracts/LPOracleAnchoredView.sol#L91). However, the product of prices of the tokens with different decimals should be considered in function [`priceProduct()`](https://github.com/dev-fountain/fountain-protocol/blob/e2c39e77c4df4a93f807abdd546a40ff76a7b483/contracts/LPOracleAnchoredView.sol#L103). <span class='major'>major</span> **Description**: In the AMM model, to determine the product of the amounts of two tokens in a pair, we do not need to cast the decimal to 18. Besides, doing this kind of casting may result in the loss of accuracy if one of the tokens in a pair has the decimal greater than 18. ```solidity= function reserveProductAndTotalSupply(string memory symbol) internal view returns(uint totalSUpply,uint product) { OracleTokenConfig memory config = CTokenConfigs[symbol]; IDexPair dexPair = IDexPair(config.underlying); totalSUpply = dexPair.totalSupply(); (uint112 reserve0, uint112 reserve1,) = dexPair.getReserves(); uint decimal0 = OracleERC20(dexPair.token0()).decimals(); uint decimal1 = OracleERC20(dexPair.token1()).decimals(); uint amount0 = uint(reserve0).mul(1e18).div(10 ** decimal0); uint amount1 = uint(reserve1).mul(1e18).div(10 ** decimal1); product = amount0.mul(amount1); } ``` **Recommendation**: We suggest removing the decimal alignment or do not use this contract for tokens with decimals greater than 18 otherwise there can be a loss of accuracy **Result**: Fixed in commit [dd9475ebc63c5fbbb396c4c01fbfdb59d8821896](https://github.com/dev-fountain/fountain-protocol/commit/dd9475ebc63c5fbbb396c4c01fbfdb59d8821896). ### Medium none ;) ### Minor none ;) ### Informational 1. Typo in function return values<span class='info'>Informational</span> **Description**: There is a typo in the return values of function [`reserveProductAndTotalSupply()`](https://github.com/dev-fountain/fountain-protocol/blob/e2c39e77c4df4a93f807abdd546a40ff76a7b483/contracts/LPOracleAnchoredView.sol#L91). The `totalSUpply` should be spelled like `totalSupply`. The variables should be spelled in _camel_ format. **Recommendation**: `totalSUpply` -> `totalSupply`. **Result**: Fixed in commit [11f434ccfa13f9ea49d05259c4b0f5e411322aa6](https://github.com/dev-fountain/fountain-protocol/commit/11f434ccfa13f9ea49d05259c4b0f5e411322aa6). 2. Magic Numbers **Description**: There are some _magic numbers_ in the code deck. For example, `1e28` in [Line 67](https://github.com/dev-fountain/fountain-protocol/blob/e2c39e77c4df4a93f807abdd546a40ff76a7b483/contracts/LPOracleAnchoredView.sol#L67), `1e10` in [Line 82](https://github.com/dev-fountain/fountain-protocol/blob/e2c39e77c4df4a93f807abdd546a40ff76a7b483/contracts/LPOracleAnchoredView.sol#L82) and [Line 87](https://github.com/dev-fountain/fountain-protocol/blob/e2c39e77c4df4a93f807abdd546a40ff76a7b483/contracts/LPOracleAnchoredView.sol#L87). <span class='info'>Informational</span> **Recommendation**: Make these magic numbers constant values with comments. **Result**: Improved in commit [bce7296eedc2922fa6ea0ab42a0d718b3ee1ef31](https://github.com/dev-fountain/fountain-protocol/commit/bce7296eedc2922fa6ea0ab42a0d718b3ee1ef31) and [d441a1b0561caf2fbf3065c8266df80381904ac6](https://github.com/dev-fountain/fountain-protocol/commit/d441a1b0561caf2fbf3065c8266df80381904ac6). 3. Unnecessary ordering between `tokenA` and `tokenB` in function [`priceProduct()`](https://github.com/dev-fountain/fountain-protocol/blob/e2c39e77c4df4a93f807abdd546a40ff76a7b483/contracts/LPOracleAnchoredView.sol#L103). <span class='info'>Informational</span> **Description**: In this function, it purposely changes the order of `tokenA` and `tokenB` and saves the symbol of the token that has a smaller token address in variable `symbol0` and the other in `symbol1`. The orders of the tokens do not change the result of the product (`product = price0.mul(price1)`). ```solidity= function priceProduct(string memory symbol) internal view returns(uint product){ OracleTokenConfig memory config = CTokenConfigs[symbol]; string memory symbol0; string memory symbol1; if(config.tokenA < config.tokenB){ symbol0 = config.symbolA; symbol1 = config.symbolB; }else{ symbol0 = config.symbolB; symbol1 = config.symbolA; } uint price0 = oraclePrice(symbol0).rate; uint price1 = oraclePrice(symbol1).rate; product = price0.mul(price1); } ``` **Recommendation**: Token symbols can be assigned directly without checking the token orders. **Result**: Revised in commit [ffc99f59d054e78701de8a0a8899faa0f4c33326](https://github.com/dev-fountain/fountain-protocol/commit/ffc99f59d054e78701de8a0a8899faa0f4c33326). --- ## Disclaimer Verilog receives compensation from one or more clients for performing the smart contract and auditing analysis contained in these reports. The report created is solely for Clients and published with their consent. As such, the scope of our audit is limited to a review of code, and only the code we note as being within the scope of our audit detailed in this report. It is important to note that the Solidity code itself presents unique and unquantifiable risks since the Solidity language itself remains under current development and is subject to unknown risks and flaws. Our sole goal is to help reduce the attack vectors and the high level of variance associated with utilizing new and consistently changing technologies. Thus, Verilog in no way claims any guarantee of security or functionality of the technology we agree to analyze. In addition, Verilog reports do not provide any indication of the technologies proprietors, business, business model, or legal compliance. As such, reports do not provide investment advice and should not be used to make decisions about investment or involvement with any particular project. Verilog has the right to distribute the Report through other means, including via Verilog publications and other distributions. Verilog makes the reports available to parties other than the Clients (i.e., “third parties”) – on its website in hopes that it can help the blockchain ecosystem develop technical best practices in this rapidly evolving area of innovation.