Bug Found 🐛: We discovered a bug where the prices of assets fetched from the UnilendV2oracle
contract using the getChainLinkAssetPrice
function are returned as Zero.
What is UniLend?
UniLend Protocol is a permissionless decentralized money market protocol with lending and borrowing service through smart contracts. UniLend enables users to utilize their cryptocurrencies by supplying collateral to the network that may be borrowed by pledging over-collateralized cryptocurrencies. This creates a secure lending environment where the lender receives a compounded interest rate annually (APY) paid by the borrowers.
In this article, we are going to be using the latest version UniLend V2. UniLend is currently live on the Sepolia and zkEVM Testnet.
Playing around with UniLendV2
We played, we liked, we wrote —> that is what this article is; it is our review of the UniLendV2.
Why UniLend? UniLend is completely market-driven. This means there are multiple scenarios under which you need to test/simulate how UniLend Protocol functions. This makes UniLend ideal for BuildBear to test it.
Please note, for a thorough review of UniLend, it is imperative that we do a test that pretty much covers all the types of transactions that you will execute on UniLend. That is the (a) Deposit and (b) Borrow transactions, (c) the payback, etc etc. However, the MOST important of all is to be able to see the performance of the dApp with the manipulation of the time. This is WHAT THIS TEST IS ABOUT! It is way larger than you think. We will NOT just lend and borrow; we will manipulate the system to be able to do an edge to edge testing.
We could simply test on the Sepolia Testnet, but then:
You get the drill. It's basically a lock-out. Cannot use Sepolia Testnet.
Could we do the local hardhat fork or anvil fork? Without a doubt. But then, we would need to take some pain in impersonating some accounts to get some ERC20 Tokens; do some more hacks to be able to “see” our transactions and the outcome of each of those and whatnot. Hence, {shameless self-sell} we utilized BuildBear.io to create a Private Testnet of the Sepolia Testnet. This allowed us to effectively utilize the UniLendV2 front end.
NOTE: Since we are (obviously) a premium user of BuildBear, the chainId
that we get from BuildBear is the same chainID that we are forking. Eg, the private Testnet that we created on BuildBear (Name: batman)[ We got a custom name] also has the chainId 11155111
, since this Testnet is a fork of the Sepolia.
Set-up before the testing: Using our Private Testnet Faucet to mint 20K DAI
Transaction 1: Lending 20K DAI into the UniLendV2 Protocol
Quick Side Note:
Transaction 2: Borrowing 5K Matic
We borrowed 5K Matic using the 20K DAI deposited as collateral. At borrow APY of 2.100% With this borrowing and the math used by UniLendV2 Protocol, our Health Factor was 3.15 after the borrowing.
Transaction 3: Lending 5k UFT Tokens
Transaction 4: Lending 5k USDC Tokens
The REAL Test
Advancing the time for a year (Using the BuildBear utility tools we were able to Advance time by a year as shown below).
Executing different scenarios
In order to facilitate this, it is crucial to have the following abilities:
Case 1: The price of Assets Remains the same || The simplest of the test
Repaying the Matic we have Borrowed with interest.
Redeeming USDC, UFT, and DAI Tokens we received from our lending positions.
UnilendV2oracle
and Altered the USDC oracle source address to [0xf46ba822fFb594a2fFcaeCa9994075FD40529059] to change the price of the USDC Token [0x6f14C02Fc1F78322cFd7d707aB90f18baD3B54f5].We encountered a Bug 🐛
Then while fetching the price of the USDC
[0x6f14C02Fc1F78322cFd7d707aB90f18baD3B54f5] Using getChainLinkAssestPrice
the function we encountered the Call_exception
error. As shown below.
After further inspection, we also found the price of the other tokens that are listed on UniLendV2 are fetching as Zero. (Weth Token Address-0xeD43f81C17976372Fcb5786Dd214572e7dbB92c7)
When we passed the Source Address of the USDC [ 0xf46ba822fFb594a2fFcaeCa9994075FD40529059] into the getChainLinkAssestPrice
we got the price As Follows.
For the purpose of testing the issue, we have used two contracts (both instances of AggregatorV3Interface) as assets and sources and vice versa.
The issue seems to be fixed in GitHub, and this is the code
function getChainLinkAssetPrice(address asset) public view returns (int256 price) {
AggregatorV3Interface source = assetsOracles[asset];
if(address(source) != address(0)){
price = getLatestPrice(source);
}
}
But while testing we got behaviour similar to
function getChainLinkAssetPrice(address asset) public view returns (int256 price) {
AggregatorV3Interface source = assetsOracles[asset];
if(address(source) != address(0)){
price = getLatestPrice(asset); // This is an issue
}
}
We tested this using a script and storing the value of the asset and the source as
// address[] assets, address[] sources
["0xf46ba822fFb594a2fFcaeCa9994075FD40529059", "0xf0cd67e684fb8bb227c7d9dc6ff96184c9a72e7c"], ["0xf0cd67e684fb8bb227c7d9dc6ff96184c9a72e7c", "0xf46ba822fFb594a2fFcaeCa9994075FD40529059"]
Both of the contracts implement AggregatorV3Interface
and return different values upon invocation by the getLatestPrice
function.
The contract 0xf0cd67e684fb8bb227c7d9dc6ff96184c9a72e7c
returns 1000000000000000
The contract 0xf46ba822fFb594a2fFcaeCa9994075FD40529059
returns 22
Upon calling getChainLinkAssetPrice
function with 0xf0cd67e684fb8bb227c7d9dc6ff96184c9a72e7c
it is supposed to return 22
(because its source is 0xf46ba822fFb594a2fFcaeCa9994075FD40529059
) but it returned 1000000000000000
Similarly, upon calling getChainLinkAssetPrice
function with 0xf46ba822fFb594a2fFcaeCa9994075FD40529059
it is supposed to return 1000000000000000
(because its source is 0xf0cd67e684fb8bb227c7d9dc6ff96184c9a72e7c
) but it returned 22
The issue seems to be fixed in GitHub, but the deployed code is behaving in this manner
We have reported the bug to the UniLend team, and they have also confirmed that the changes on GitHub are not live on Sepolia Yet.
Due to this bug, we encountered difficulties in executing Test Case 2 and Case 3.
Conclusion: The BuildBear impersonate feature, which enabled us to act as the owner of UnilendV2oracle
and change the Price oracle Address, played a crucial role in identifying the issue.
Using BuildBear for your QA
If you are DeFi Web3 App and you are looking to either
Come talk to us at team@buildbear.io We can help you create your own, 100% customized testing environment, so that you can use it without any hassle.
NOTE: Information in this article shouldn’t be taken as Finance Advice.
Author: chandan