As of 3 Nov 2026, UniFarm has 5 audit reports by 2 security firms on Trustblock; the latest is by QuillAudits, dated 8 Aug 2022. Those reports list no open critical findings.
Record last updated . It holds audits, findings and contracts up to Nov 2026, and incidents up to Oct 2026. Trustblock does not review code.
Newest first
| Audit | Security firm | Date | Scope | Critical findings | Report |
|---|---|---|---|---|---|
| unifarm - Bridge | Security firm: QuillAudits | Date: | Scope: Not recorded (see the report) | No open critical findings | Open · quillaudits.com |
| UniFarm | Security firm: Zokyo | Date: | Scope: Not recorded (see the report) | No open critical findings | Open · IPFS |
| AMM_unifarm | Security firm: QuillAudits | Date: | Scope: Not recorded (see the report) | No open critical findings | Open · quillaudits.com |
| Unifarm - Vesting | Security firm: QuillAudits | Date: | Scope: Not recorded (see the report) | No open critical findings | Open · quillaudits.com |
| OpenDefi - Unifarm Audit Audit · firm’s term: audit | Security firm: QuillAudits | Date: | Scope: Files named in the report | No open critical findings | Open · quillaudits.com |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 4 |
| Medium | 3 | 0 | 15 |
| Low | 9 | 2 | 21 |
There is possibility of a profitable reentrancy attack in removeLiquidity(). This is because a low level call is used in transferLPFee() function which allows the caller to call any malicious code from another contract. Using this multiple rewards for same liquidity position can be harvested.For example, Let’s say the 1st liquidity position by an LP is 1000 USDC. After that a user does cross-chain transfer. Now the LP sees that he has some rewards available to claim. Then he adds a 2nd position of say 5000 USDC tokens. Now when the user does a reentrant call via low level call in transferLpFee, he will be able to get twice the reward for the same liquidity position. This is possible because although the index of the first liquidity position will be used for the reentrant call, 2000 or more USDC tokens will need to be withdrawn for claiming more rewards which will be taken from the LP’s second liquidity position directly. The rest of the liquidity he will still be able to claim via transferOut.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportA malicious owner can deploy a dummy or fake setu token and overwrite the existing metadata of already added setu token using addTokenMetadata using addTokenMetadata() function. For example, let's say setuUSDC was deployed using addBridge() for USDC token, then a malicious owner can overwrite the bridgeTokenMetadata mapping for the USDC setuToken. This is possible if the owner had deployed an ERC20 token with symbol as setuUSDC and the address of this token is passed as a parameter to the addTokenMetadata() function. This attack can be coupled with A.1 to amplify this attack. In addition to this, overwriting to bridgeTokenMetadata can also be done via _deploySetuToken if a setuToken with the same ticker and symbol is deployed again by an owner.
Open the reportburnTokens() function can be called by the owner to burn tokens from any account, even from the accounts that it currently does not own. Here the owner is a bridge contract, so this intended design is fine. But this can be exploited by a malicious admin if he calls renounceOwnership() and transfer ownership of the contract to himself. Also lockedTokens() function can be called by the owner to burn tokens from any account, even from the accounts that it currently does not own. Also a malicious owner can mint more setuTokens and use it to drain liquidity from the Liquidity Pools by calling the transferOut() function.
Open the reportsafeWithdrawLiquidity() can be used by a malicious owner to withdraw all the liquidity of any token.
Open the reportupdateFeeConfig() allows updating of tokenBridge's fee at any time. Also the _feeInBips parameter has no upper limit and can be exploited by a malicious admin to set very high fees without anyone noticing or taking action. Also _feeInBips parameter lacks zero value check as well which can lead to unintended issues such as no fees getting paid by users. updateEpochLength() allows to update the epochLength of bridge anytime which can lead to unintended issues and bugs.
Open the reportAlthough the childToken is an upgradeableToken, it can never be upgraded by the owner of the Registry Contract. It can only be upgradedby the proxyAdmin. The Registry contract is the owner of the proxyAdmin, not the owner of the Registry contract.
Open the reportIf a user buys booster packs using buyBoosterPacks() and then add liquidity using addLiquidity(), then the user will lose his currently bought boosters due to overwriting of boosterEndEpochIndex for that particular liquidity position. For example, let's say user buys 1000 booster packs for token USDC, with _index parameter specified as 1 (for which he has not added any liquidity yet and let's say currentEpochIndex is 50). This will set boosterEndEpochIndex to 1049. Now at epoch say 60, and the user adds liquidity using addLiquidity() with _noOfBoosters as zero, the boosterEndEpochIndex will get overwritten to 60 resulting in loss of boosters bought.
Open the reportPausable modifier from the Openzeppelin is not used. Calling pauseTokens() does not actually pause any functionality in the contract like locktokens() or unlocktokens().
Open the reportThere are no sanity checks for bridgeType in addBridge() function. According to the docs provided there can be a maximum of 2 bridge types- liquidity bridge and child bridge (or liquidity + child bridge). BridgeUpgradeable contract's transferIn() which has if statements depending on bridgeType, will not get executed if the bridgeType is incorrectly set other than value 0 or 1. Also this could lead to the possibility that the crossChainTransferIn() is done successfully without paying any fees (plus the user gets additional setutokens minted which would actually should have been burned).
Open the reportIf _deploySetuToken is called externally without adding any bridge via addBridge(), the function disableBridge() will revert always for the setuToken's primary token. Also updateFeeConfig() and updateEpochLength() will not work as it will revert due to the first require check.
Open the reportIf an existing bridge is removed using removeBridge() which contains liquidity provided by LPs, they will not be able to claim back their liquidity. This would also result in LPs unable to claim any fees accumulated till that point as well.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the report__gap variable is not required in BridgeUpgradeable contract (declared at the end of the contract) because __gap variables are generally used in Base contracts and not in Child contracts. It may lead to unintended issues or mistakes.
Open the reportAccording to the docs feeType can only be 0 or 1. But updateFeeConfig() allows to set fee for any fee type.
Open the reportMissing zero address check for _newBridgeAddress parameter in the updateBridgeAddress() function. This could lead to transfer of ownership of newChildToken to zero address if deployChildToken() function is called. Similarly if addBridge() function is called, _deploySetuToken() function will be called internally, leading to transfer of ownership of setuToken to zero address.
Open the reportMissing zero address check in for _admin parameter in initialize() function.
Open the reportSolidity naming conventions are not followed thoroughly. For example: Internal function should be named _addPassedEpochs() and external function should be named addPassedEpochs(). Also as _deploySetuToken() is a public function, it should be named deploySetuToken() instead.
Open the reportThe functions addLiquidity(), crossChainTransferIn(), crossChainTransferOut(), transferIn() can be vulnerable to reentrancy attack if setutoken is malicious.
Open the reportThe if statement checks whether the mapping is zero and then deletes the mapping. But this is not needed because delete does the same thing as setting the mapping to zero value.
Open the reportA reentrant attack is possible via transferOut() function because of the low level call used in calculateBridgingFees() function. The low level call allows another account to call malicious code although in this case it would just be a griefing attack as a simple reentrant call would only result in the caller paying more fees.But there is still the possibility of a cross-contract reentrancy attack if the contracts in question used shared variables which can not even be mitigated by using non-Reentrant modifier from Openzeppelin. Note that the function crossChainTransferIn() will also be vulnerable to the same attack as transferOut is being called internally there.
Open the reportThe renounceOwnership function can be called accidentally by the admin leading to immediate renouncement of ownership to zero address after whichany onlyOwner functions will not be callable which can be risky.
Open the reportThe transferOwnership() function in contract allows the current adminto transfer his privileges to another address. However, inside transferOwnership() , the newOwner is directly stored into the storage owner, after validating the newOwner is a non-zero address, and immediately overwrites the current owner. This can lead to cases where the admin has transferred ownership to an incorrect address and wants to revoke the transfer of ownership or in the cases where the current admin comes to know that the new admin has lost access to his account.
Open the reportgetLPsFee() is an internal function that is not getting called anywhere.
Open the reportThe updateBoosterConfig() function lacks sanity checks for its parameters such as _perBoosterPrice and _adminAccount and thus can be accidentally set to incorrect values.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportThe report gives no description here.
Open the reportThe reports name a repository or files. Open a report to see its scope.
Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.
Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.
<head><script src="https://widget.trustblock.run/project-widget.min.js" defer></script></head><body><divdata-tb-project-widgetdata-tb-project-slug="unifarm"></div></body>
Paste the code where the label should appear. It uses no API credit and updates by itself.
Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us