K33 engaged Guardian to perform a follow-up security review of its borrowing lending platform built on top of SparkLend. From the 4th of February to the 7th of February, a team of 6 auditors reviewed the source code in scope.
- Published
- Review window
- February 4 to 7, 2025
- Language
- Solidity
- Chains
- Ethereum
- Sector
- Lending
- 0 Critical
- 0 High
- 3 Medium
- 6 Low
- 0 Informational
Scope
Overview
K33 engaged Guardian to perform a follow-up security review of its borrowing lending platform built on top of SparkLend. From the 4th of February to the 7th of February, a team of 6 auditors reviewed the source code in scope.
Issues Detected Throughout the engagement only Medium and Low issues were uncovered and promptly remediated by the K33 team which indicates an overall healthy design and implementation. Following their remediation Guardian believes the protocol to uphold the functionality described for the Lending product.
Findings 9
-
M-01 Medium User Can Pass Arbitrary Fee Amount Logical Error Acknowledged
Description
Function
borrowaccepts an arbitraryfeeAmountthrough aloancall. If K33 expects a fee to be paid on borrow, a user can just directly interact with the contract and pass afeeAmountof zero to preserve as much capital.Recommendation
Add validation on the expected
feeAmountfor K33. Alternatively, consider tieing feeAmount to a fixed percentage of the borrowed/liquidated amount rather than letting the caller supply an arbitrary fee, implement a fixed percentage model (e.g.,feeAmount = (borrowedAmount * feePercentage) /1e18).Resolution
K33 Team: We own all the wallets our customers utilize, so we are not concerned with external parties calling the contract using their own wallets.
-
M-02 Medium Failed Approvals With USDT Logical Error Resolved
Description
Function
repayapprovesamountand then callsSparkLendto repay the amount. The issue is that thepaybackAmountwithin the BorrowLogic is not necessarily equal toamountpassed, so a portion of the approved amount will be not be utilized.This will lead to DoS with tokens such as USDT which require a 0 approval initially.
Recommendation
For all allowances in K33, use
SafeERC20'sforceApprovewhich will force the allowance to go to zero initially to handle tokens such as USDT. Also, use it after an external call to set the approval to zero after the approval is no longer necessary.Resolution
K33 Team: Added a
forceApprovalfunction to the contract that performs the functionality as needed. We also reset the allowance where needed.Guardian Team: After function
swapis performed, the SwapRouter may still have some token approval leftover if the entireamountInwas not utilized. -
M-03 Medium Lost Borrow Fee Validation Acknowledged
Description
When users borrow via K33, a part of the borrowed assets is paid as a fee to the
feeAddress, which is an arbitrary passed parameter, but is validated to be a whitelisted address.However, whitelisted addresses are also the swap routers and the lending pools. This means users may choose to pay the fee to any other whitelisted address resulting in loss of funds for K33.
Recommendation
Create a separate validation for the
feeAddress.Resolution
K33 Team: If an external party wishes to utilize the contract without disrupting its function, they are free to do so.
-
L-01 Low LendingPoolAddress Points To Registry Instead Deployment Resolved
Description
The deployment script currently passes
0x02C3eA4e34C0cBd694D2adFa2c690EECbC1793eE(thePoolAddressesProviderof Spark) to theVanirconstructor, instead of passing0xC13e21B648A5Ee794902342038FF3aDAB66BE987(the SparkLendingPooladdress on Ethereum mainnet).As a result, the Vanir contract is initialized with the wrong contract reference thereby preventing it from interacting correctly with the Spark lending protocol.
If the contract is meant to integrate with Spark Lend on mainnet, the
LendingPooladdress (0xC13e21B648A5Ee794902342038FF3aDAB66BE987) should replace thePoolAddressesProvideraddress in the script.Using the
PoolAddressesProviderdirectly is incorrect in this context because K33 specifically needs the activeLendingPoolto perform supply/borrow/repay operations, not just an address provider.Recommendation
Update the constructor call in
DeployVanir(or any relevant deployment script) to use0xC13e21B648A5Ee794902342038FF3aDAB66BE987instead of0x02C3eA4e34C0cBd694D2adFa2c690EECbC1793eE.Resolution
K33 Team: Resolved.
-
L-02 Low No Controls On Liquidation Fee Amount Validation Resolved
Description
During liquidation, the user pays an additional
feeAmountfrom their collateral. ThisfeeAmountis arbitrarily set by the admin within theirLiquidationRequest, and can vary each time.Without fee validation, the fee may be too small or too large, negatively impacting the protocol and user respectively.
Recommendation
Consider adding on-chain validations for
feeAmounton liquidations, or clearly document the fee calculation behavior of your backend system.Resolution
K33 Team: We have a breakdown of the calculations documented in our backend.
-
L-03 Low Failed Liquidations With Low Target LTV Warning Resolved
Description
K33 has a target LTV for liquidation within its backend system. If the LTV which K33 is targetting has a large delta between the current LTV, all liquidation calls will fail as more amountIn is necessary than is approved and available for swap.
Recommendation
Clearly document this behavior and appropriately set the target LTV.
Resolution
K33 Team: This is dependent on providing the correct parameters, we have found a target range that works for us and can adjust it to lesser deltas if needed.
-
L-04 Low Failing Tests Warning Acknowledged
Description
The tests are meant to simulate K33's operations with current backend configurations, however numerous tests are failing. Some reasons for failure include but are not limited to: 1. Lack of pinned fork block number 2. Improper Target LTV's for partial liquidations 3. Incorrect
feeAmountcalculation within the testsAll tests should be passing prior to deployment.
Recommendation
Fix all tests and align them with K33's backend systems.
Resolution
K33 Team: Acknowledged.
-
L-05 Low No Events Emitted On Funds Rescue Event Acknowledged
Description
Two new functions has been added to the contract to enable the admin to reduce funds - ‘
transfer’ and ‘transferEth’. There are no events emitted to notify for the action happening.Recommendation
Consider if you should emit events in these two functions.
Resolution
K33 Team: We have no needs for these events, we utilize a blockchain listener that tracks all K33-related activity.
-
L-06 Low Frozen Pool Will Lead To Fail Liquidations Warning Acknowledged
Description
When the reserve configuration in
SparkLend isFrozen, supplying liquidity is prevented by repays and withdraws are permitted. If the configuration were set to frozen, most K33 liquidations would fail since functionswap()attempts to supply liquidity that wasn't used as part of the swap cost.Recommendation
Clearly document this risk.
Resolution
K33 Team: Acknowledged.
No findings match.
Put your code through the same review.
This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.
