RociFi Blog
← All posts

RociFi’s Audit Results and Improvements

2022-06-22

Jun 22

Do you even need an audit? Does it add any value? Does CompanyX audit provide any value compared to CompanyY’s? These questions are on any Solidity developer’s lips.

In this piece, we share the RociFi development team’s experience.

TL;DR: An audit is a good start but you need much more to increase the odds of a safe launch.

RociFi solves permissionless, under-collateralised lending in DeFi. To put it simply, our protocol allows you to borrow more money than you put as a collateral if your credit risk score is good enough. Our scoring engine checks your on-chain financial history and social reputation, then produces a score. No KYC is involved. As a lender, you can provide liquidity to the lending pools without lockup.

Protocol development started less than 10 months ago, but only now do we realize in retrospect how ambitious our product is. Just to name a few of the protocol’s core features

We wish we could have just forked Aave or Compound with a few tweaks and called it a day. But, in order to support the aforementioned rich features, we needed to develop a protocol from scratch.

After making the initial version, we involved auditors and our advisors to get honest feedback. We want to say a huge thanks to both Chainsulting and Certik teams for providing detailed reports and ideas for future improvements. The same goes for our advisors from the Lido.fi core tech team.

Our audit reports can be seen here: Chainsulting and Certik.

To tell the truth, most of the points raised by audits already were in the back of our minds. Still, it was super useful to get a confirmation for all the problematic or over-complicated parts of our design. This reinforced some of our ideas about further protocol architecture improvements.

A few key takeaways from our audits.

Liquidity Pools and price balancing functionality didn’t fit protocol requirements

Details: We used Uniswap Liquidity Pools (`IUniswapV2Router02` and `IUniswapV2Factory`) and our custom contract (`LiquidityFarm`) to allow anyone to deposit assets in the protocol and earn APY in form of farming rewards which paid in so-called “debt token”. The stability of the debt token is managed by the special method, `TraderInvestor.balance`. This method sells and buys debt tokens in the corresponding pool when the price fluctuates too much. `Trader.sol` contract is used to that end.

Problems:

Fix: We removed Uniswap pools and AMM functionality from the protocol and created our pools with the simple and predictable debt token price logic which can be thoroughly tested.

Relying on Chainlink Oracle for critical business logic

Details: We used Chainlink oracles and Any API when confirming the loan. Namely, *Investor.borrowFulfill* method is called from the Oracle, which in turn calls *Investor.sendFunds*.

Problems:

Fix: We refactored away Chainlink Any API and simplified the complex and cumbersome process of pushing scores in the contract. Now Chainlink is used for the price feeds only.

Security and code instrumentation

Problems:

Fix: Now — the all-important functionality can be paused when needed, i.e. kill switch. We use rich roles management and service discovery provided by Openzeppelin’s access role system. Every meaningful change in the contract will fire an event, which allows for integrations with alerting and analytics software (Dune Analytics, Subgraph, OpenZeppelin Sentinels to name a few).

Code quality

Problems:

Fix: Now — our test coverage is at 92%. Report. We have exactly 0 warnings. We have a code baseline in using Prettier and Solhint. We use Husky pre-commit hooks and Github actions to make sure new PR does not introduce regressions or diverge from the code style.

By all accounts, receiving an audit is a good metric. But, that’s only one piece of the puzzle. There are other pieces which are crucial to getting your project off the ground along with implementing the audit recommendations.

Testing-driven development

We cannot stress enough the importance of having the maximum possible test coverage of your contracts. Smart contracts engineering is not a very forgiving field. One mistake in your code can lead to a huge loss of liquidity for your customers. Not tested code should not be merged.

Hardhat is a great framework which became an industry standard. It allows you to run your tests in a rich variety of environments and provides lots of helpers and plugins.

Flexible testing environments

To properly test your Dapp, you need to deploy it to publicly accessed environments. For UI, we use Netlify branches, smart contracts are not that simple in this regard. Testnets help up to a point, but our experience with some of them was very painful. Your transactions might be stuck in the pool for hours for no reason, or block explorer may be suddenly inaccessible, and farming test ether is awkward. And what’s more important, no testnet is close enough to the target mainnet in terms of integrations, specific ERC-20 tokens and AMMs.

This is why we ended up spinning our fork node using Hardhat. And recently we switched to the Tenderly Forks, which also works quite well and allows for a rich debugging experience.

Tooling

Solidity development is still in its infancy and many developers are debugging their code using `console.log`. Luckily for us, we soon enough discovered Tenderly, which provides excellent debugging experience with breakpoints and expressions evaluation. We highly recommend any smart contract developer to integrate Tenderly in their environment.

Security and operational monitoring

Monitoring your contracts is essential. As an absolute minimum, you should have alerts for any non-sanctioned privileged transactions, big changes in liquidity and large value transactions, spikes in reverts and collateral price changes.

OZ Sentinels is a good start for basic alerting, and Forta Network bots provide a flexible and scalable framework for detecting on-chain events of any complexity. Alerts can be then filtered and routed to the pagerduty software of your choice.

Release and change management

Smart contracts development is no different from traditional software engineering and change management is an integral part of it. These principles may sound trivial, but following them increases the quality of your delivery.

Smart contract development is a complex venture where audits service a critical, but ultimately, only one small piece of the puzzle. Having a robust testing and implementation framework, coupled with strong advisors to offer feedback at every turn significantly increases your chances of success (a shilling tweet from Elon Musk never hurts either).

This is the approach that RociFi has taken for its upcoming Mainnet launch on Polygon. Minus the tweet from Elon, although if interested, holla at us Elon!

After launch, we will implement a bug bounty program designed to further identify and mitigate threats to our protocol and stakeholders.

________

RociFi is bringing under-collateralized credit to Web3