Given the opportunity to review the design document and related source code of the Litra protocol, we outline in the report our systematic approach to evaluate potential security issues in the smart contract(s) implementation, and provide additional suggestions or recommendations for improvement. Our results show that the given version of smart contracts can be further improved due to the presence of several issues related to either security or performance. This document outlines our audit results.
Litra Finance is an NFT liquidity protocol that wraps NFT into fungible ERC20 tokens to improve trading accuracy and provide more basic liquidity targets. Combining an automated centralized liquidity AMM with a customized curve provides traders with the ultimate trading experience with low slippage, while reducing impermanent losses for liquidity providers. The introduction of the veToken model encourages liquidity providers to actively and consistently provide liquidity for greater returns, which also aligns the interests of all parties.
Item | Description |
---|---|
Client | Litra Finance |
Website | https://litra.finance/ |
Type | Smart Contract |
Languages | Solidity |
Platform | EVM-compatible |
The codebase is delivered to us in a compressed file called litra-contracts.rar. This security audit was performed for checksum of 0a3e607cfff4605d061e95a8fac91786cba7d92d399bfb4019b0dc4ce1b929d8
.
Below are the files in scope for this security audit and their corresponding SHA256 hashes.
Filename | SHA256 |
---|---|
./dao/admin/EmergencyAdminManaged.sol | c1673836bea9343a262747c4df381fa44c9f02cf579f0d78e7faea6272cca0a9 |
./dao/admin/OwnershipAdminManaged.sol | 6cdd35621608154eae6e9fc07460e411fc3a879220aeb97a9a3e1448c429b145 |
./dao/admin/ParameterAdminManaged.sol | 625636c12957e5a15d41807b0d37474d77a2f33247b16bb1273c0fbf85454a5e |
./dao/admin/Stoppable.sol | fa47ef841e4558d14b6a67865043469018c599a04631bb60a0b40ee727dc902d |
./dao/FeeManager.sol | 0a04c5f40c77682e06312082204139cf1d790c11c7bea5dd7f0771877518314a |
./tokenize/NFTVault.sol | b18c08f1f24c05e4b9eb1515b88a3496de13c5c72af4dab627ebf2b980b6b973 |
./tokenize/WrappedNFT.sol | c6fde303290d72aea41b389a54f964850c8e1349bac30b3d1d5fdc60fa44a968 |
This is the checksum after all fixes for the issues found in the audit have been checked in: 9303970128295bc8c223712bfbd56f92826d3821b4f51798eca9a38f97643b5b
And the files in scope and their SHA256 hashes after this security audit issue has been fixed.
Filename | SHA256 |
---|---|
./dao/admin/EmergencyAdminManaged.sol | 493960567fea3e9e5e3aa0b52e5730540642a669e48add8a1012607e8cb4dcb5 |
./dao/admin/OwnershipAdminManaged.sol | 972be6bd2fd8656c6f7ab3dbf7cf0b2067bd0c5621fa15632d831e9b04554abd |
./dao/admin/ParameterAdminManaged.sol | 6dd0b26eb7891129aa1a8c99f060a181df6c21ed5e0a07f68422e83f325943df |
./dao/admin/Stoppable.sol | fa47ef841e4558d14b6a67865043469018c599a04631bb60a0b40ee727dc902d |
./dao/FeeManager.sol | 5bf86ec90832c50728952f4a570d4637009137ccac2ca95642180ad7ea4220f2 |
./tokenize/NFTVault.sol | c1e1b30ea88b062e12e3a04fb369eb2539be17f22fa451c7012b59219c8872e9 |
./tokenize/WrappedNFT.sol | c6fde303290d72aea41b389a54f964850c8e1349bac30b3d1d5fdc60fa44a968 |
Version | Date | Description |
---|---|---|
0.1 | April 07, 2023 | Initial Draft |
0.2 | April 08, 2023 | Release Candidate #1 |
1.0 | April 21, 2023 | Final Report |
Litra Finance is an NFT liquidity protocol, and within the scope of observable security audits its main functions are the components NFTVault, FeeManager and Admin.
As shown above, this involves multiple interactions between a user who (wraps) his NFT into a WrappedNFT via Litra Finance and a user who (unwraps) his WrappedNFT into an NFT via Litra Finance. During the audit, we assume the user could be malicious, which means all messages sent to Litra Finance are untrusted.
We enumerated the attack surface based on this assumption.
Supremacy is a leading blockchain security agency, composed of industry hackers and academic researchers, providing clients with a one-stop security solution for the whole life cycle with our technology precipitation and innovative research.
We are reachable at Telegram (https://t.me/SupremacyInc), Twitter (https://twitter.com/Supremacy_CA), or Email (contact@supremacy.email).
For the purpose of this assessment, we adopt the following terminology. To classify the severity of our findings, we determine the likelihood and impact (according to the CVSS risk rating methodology).
We categorize the findings into four distinct categories, depending on their severity. These severities are derived from the likelihood and the impact using the following table, following a standard risk assessment procedure.
As seen in the table above, findings that have both a high likelihood and a high impact are classified as critical. Intuitively, such findings are likely to be triggered and cause significant disruption. Overall, the severity correlates with the associated risk. However, every finding's risk should always be closely checked, regardless of severity.
The table below summarizes the findings of the audit, including status and severity details.
ID | Severity | Description | Status |
---|---|---|---|
1 | Critical | WrappedNFT forcible minting |
Fixed |
2 | Critical | Theft of any user's NFT |
Fixed |
3 | Medium | Potential fee loss |
Fixed |
4 | Medium | Centralization risk |
Confirmed |
5 | Low | Unchecked zero-address |
Fixed |
6 | Low | Unchecked return values |
Fixed |
7 | Informational | Missing event records |
Fixed |
8 | Informational | Best Practices |
Fixed |
9 | Informational | Best Practices |
Fixed |
WrappedNFT forcible minting [Critical]
• Severity: Critical • Likelihood: High • Impact: High
• Status: Fixed
Description: NFTVault::wrap()
is a function that converts ERC721 (NFT) to ERC20 (WrappedNFT). However, since #L90 assigns wnftId to wnftIds[WrappedNFT]
and _nftAddr
is controllable, resulting in WrappedNFT being arbitrarily mint.
NFTVault::wrap(WrappedNFT, 0)
wrap()
will call WrappedNFT::transferFrom()
externally, and since WrappedNFT is a standard ERC20 Token, it can be executed normally, but without actually transferring the Token, because _value
is 0
wnftId
through #L61, it will not enter the CREATE
procedure, but the else
condition, and the wnft
obtained through #L94 is WrappedNFT itself, so the subsequent procedure, will be directly for the caller
Mint WrappedNFTRecommendation: Delete #L90 from NFTVault.sol
Theft of any user's NFT [Critical]
• Severity: Critical • Likelihood: High • Impact: High
• Status: Fixed
Description: Based on the premise of Critical-1, a hacker can force the minting of any number of WrappedNFTs under a certain NFT series. however, in the NFTVault::unwrap()
function, it allows the user to submit 1e18
WrappedNFTs and redeem the NFTs of that series. thus, the hacker can premeditatedly obtain all the deposited NFTVault in NFTVault and thus theft all users' NFTs by calling NFTVault::unwrap()
.
Recommendation: Refer to the first recommendation.
Potential fee loss [Medium]
• Severity: Medium • Likelihood: High • Impact: Low
• Status: Fixed
Description: It is not recommended to leave the initial fee to the user to set, because due to the atomic nature of the transaction, it is not possible to charge a fee for WrappedNFTs created within a single transaction anyway. If the user sets both Wrap
and Unwrap
fees to 0
after the WrappedNFT is created, no fee will be charged during the window until the parameterAdmin sets the fee again, thus, causing some financial loss.
Recommendation: When the user calls NFTVault::Wrap()
or NFTVault::Unwrap()
, call FeeManager::setWrapFee()
externally to set the fee instantly before NFTVault transfers the fee (need to add access control in FeeManager).
Centralization risk [Medium]
• Severity: Medium • Likelihood: Low • Impact: High
• Status: Confirmed
Description: In the Litra Finance protocol, privileged accounts exist that play a key role in managing and regulating the operation of the entire system (e.g., configuring various parameters and setting stopped parameters). It also has the privilege of controlling or managing the flow of assets managed by the protocol.
Our analysis shows that privileged accounts need to be scrutinized. In the following, we will examine privileged accounts and the associated privileged access in the current contract.
Note that if the privileged owner account is a plain EOA, this may be worrisome and pose counter-party risk to the protocol users. A multi-sig account could greatly alleviate this concern, though it is still far from perfect. Specifically, a better approach is to eliminate the administration key concern by transferring the role to a community-governed DAO. In the meantime, a timelock-based mechanism can also be considered as mitigation.
Recommendation: Initially onboarding could can use multisign wallets or timelocks to initially mitigate centralization risks, but as a long-running protocol, we recommend eventually transfer the privileged account to the intended DAO-like governance contract. All changed to privileged operations may need to be mediated with necessary timelocks.
Eventually, activate the normal on-chain community-based governance life-cycle and ensure the intended trustless nature and high-quality distributed governance.
Unchecked zero-address [Low]
• Severity: Low • Likelihood: Low • Impact: Low
• Status: Fixed
Description: Adding the requirement for non-zero address to target.
EmergencyAdminManaged::commitEmergencyAdmin()
OwnershipAdminManaged::commitOwnershipAdmin()
ParameterAdminManaged::commitParameterAdmin()
Recommendation: Add the code.
Unchecked return values [Low]
• Severity: Low • Likelihood: Low • Impact: Low
• Status: Fixed
Description: The NFTVault contract uses the EnumerableSet library to add
and remove
values to the set. Both functions return boolean values when they're called:
Therefore, there should be a check to validate that the addition or removal from the set was correct. Otherwise, every time the function is called, the owner will have to check using getter functions.
Recommendation: Check the return values using either assert() or require() statements.
Missing event records [Informational]
Status: Fixed
Description: In the EmergencyAdminManaged
, OwnershipAdminManaged
, ParameterAdminManaged
, and Stoppable
contracts, privileged accounts can set Admin privileges and stopped
status through privileged functions respectively, but no event logging is performed. And, in FeeManager
contract, user will call setWrapFee()
& setUnwrapFee()
to change the status, but no event logging.
Events are important because off-chain monitoring tools rely on them to index important state changes to the smart contract(s).
Recommendation: Consider emitting events when state changes are performed in the EmergencyAdminManaged
, OwnershipAdminManaged
, ParameterAdminManaged
, Stoppable
and FeeManager
contract.
Best Practices [Informational]
Status: Fixed
Description: Some storage variables should be immutable Marking these as immutable (as they never change outside the constructor) would avoid them taking space in the storage.
Recommendation: Change the code in #L17.
Best Practices [Informational]
Status: Fixed
Description: In the EmergencyAdminManaged
, OwnershipAdminManaged
and ParameterAdminManaged
contracts, privileged accounts can each set administrative privileges via privileged functions, where a transition account future
exists so that the future
account in the future can be upgraded to administrator by calling the applyAdmin() privilege function.
However, the call to applyAdmin() does not reset future
, making the calling account both Admin
and future
.
Recommendation: Add the code.
This audit report does not constitute investment advice or a personal recommendation. It does not consider, and should not be interpreted as considering or having any bearing on, the potential economics of a token, token sale or any other product, service or other asset. Any entity should not rely on this report in any way, including for the purpose of making any decisions to buy or sell any token, product, service or other asset. This audit report is not an endorsement of any particular project or team, and the report does not guarantee the security of any particular project. This audit does not give any warranties on discovering all security issues of the smart contracts, i.e., the evaluation result does not guarantee the nonexistence of any further findings of security issues, also cannot make guarantees about any additional code added to the assessed project after the audit version. As one audit-based assessment cannot be considered comprehensive, we always recommend proceeding with independent audits and a public bug bounty program to ensure the security of smart contract(s). Unless explicitly specified, the security of the language itself (e.g., the solidity language), the underlying compiling toolchain and the computing infrastructure are out of the scope.