As of 2 Nov 2026, Nut DeFi has 1 audit report on Trustblock, by CertiK, dated 20 Jan 2025. That report lists no open critical findings. It also holds 1 deployed contract on 1 chain.
Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Trustblock does not review code.
Newest first
| Audit | Security firm | Date | Scope | Critical findings | Report |
|---|---|---|---|---|---|
| Nut DeFi - Audit | Security firm: CertiK | Date: | Scope: 1 address on BNB Chain | No open critical findings | Open · skynet.certik.com |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 3 | 0 |
| Medium | 6 | 0 | 8 |
| Low | 6 | 0 | 10 |
In the contract, functions modified with `onlyWhiteList` can be validated as long as the address is in the fee whitelist or fund address: `nut_live.sol` ```solidity=402 modifier onlyWhiteList() { address msgSender = msg.sender; require(_feeWhiteList[msgSender] || msgSender == fundAddress || msgSender == _owner, "nw"); _; } ``` Therefore, the following functions can be executed as long as the address is in the fee whitelist: - setFundAddress() - setFeeWhiteList() - setSwapPairList() - setLPHoldCondition() - setExcludeLPProvider() - setRewardGas() - startTrade() - setLPRewardTimeDebt() - setRemoveLPFee() - setBuyFee() - setSellFee() the following functions can be executed as long as the address is fund address: - setAutoLPBurnSettings() - setFundAddress() - setFeeWhiteList() - setSwapPairList() - setLPHoldCondition() - setExcludeLPProvider() - setRewardGas() - startTrade() - setLPRewardTimeDebt() - setRemoveLPFee() - setBuyFee() - setSellFee() The following functions can be executed if the address is both the fund address and the fund address is included in the fee whitelist: - updateLPAmount() - setExcludeReward() However, these are core permission functions, and the fee whitelist or fund address should not have such high-level permissions to execute them. Additionally, if the project team renounces ownership, the contract can still be controlled via previously added fee whitelist addresses or the fund address, which poses a certain centralization risk.
Open the reportIn the `NutToken` contract, the system mistakenly categorizes the action of adding liquidity (LP) as a **selling action**, which results in an improper application of transaction fees. Specifically: When a user adds liquidity, the contract charges a **2% fee** on the transferred `NUT` tokens: - **1% is sent to the dead address**. - **1% is sent to the NUT contract address**. According to the contract's intended design, **adding liquidity should not incur any fees**. The action of adding liquidity (transferring tokens to the liquidity pool) is not a "sell" transaction but rather a contribution to the pool, which benefits the ecosystem. This discourages users from participating in liquidity provision, potentially harming the liquidity of the `NUT` token on decentralized exchanges.
Open the reportWhen the amount of NUT tokens accumulated in the NUT token contract reaches a certain threshold, a swap will be triggered during the transfer of NUT tokens. However, this swap will update some variables, leading to unintended updates in the state of the pair or NUT token: 1. If USDT is transferred first, then NUT is transferred (which triggers a swap), and then LP tokens for the mainPair are minted (e.g., using `swapRouter`'s `addLiquidity()` to add liquidity), the initially transferred USDT will be synced to the pair's reserve during the swap, resulting in a minting of 0 LP tokens. Due to the pair's LP minting check, the transaction will fail. 2. If `swapRouter`'s `addLiquidity()` is used and a swap is triggered during the transfer of NUT tokens, the `transfer` of NUT will set the previously transferred `_lastMaybeLPAddress` to 0, and since `mint()` for the pair hasn't been called yet, the LP token amount will be 0. **The user adding liquidity will not be added as an LP provider, causing a legitimate liquidity provider to not receive rewards.**
Open the reportWhen a user successfully adds liquidity for the first time, the reward timestamp `_lastLPRewardTimes` will change from 0 to the current time of adding liquidity, and the user will be added to the LP provider list: `nut_live.sol` ```solidity=540 if (lastMaybeAddLPAddress != address(0)) { _lastMaybeAddLPAddress = address(0); uint256 lpBalance = IERC20(mainPair).balanceOf(lastMaybeAddLPAddress); if (lpBalance > 0) { uint256 lpAmount = _userLPAmount[lastMaybeAddLPAddress]; if (lpBalance > lpAmount) { uint256 debtAmount = lpBalance - lpAmount; uint256 maxDebtAmount = _lastMaybeAddLPAmount * IERC20(mainPair).totalSupply().div(_balances[mainPair]); if (debtAmount > maxDebtAmount) { excludeLpProvider[lastMaybeAddLPAddress] = true; } else { _addLpProvider(lastMaybeAddLPAddress); _userLPAmount[lastMaybeAddLPAddress] = lpBalance; uint256 blockTime = block.timestamp; if (0 == _lastLPRewardTimes[lastMaybeAddLPAddress]) { _lastLPRewardTimes[lastMaybeAddLPAddress] = blockTime; } } } } } ``` However, when a user subsequently removes all their liquidity, there is no mechanism to remove the user from the LP provider list, and the reward calculation time does not stop : `nut_live.sol` ```solidity=623 if (isRemoveLP) { if (!_feeWhiteList[to]) { takeFee = true; uint256 liquidity = (amount * ISwapPair(_mainPair).totalSupply() + 1).div(balanceOf(_mainPair) - 1); if (from != address(_swapRouter)) { liquidity = (amount * ISwapPair(_mainPair).totalSupply() + 1).div(balanceOf(_mainPair) - amount - 1); } require(_userLPAmount[to] >= liquidity, ">uLP"); _userLPAmount[to] -= liquidity; } } ``` This will result in the user's reward time continuing to accrue even when they do not hold any LP tokens. As long as they hold a certain amount of LP tokens before the reward cycle ends, they can claim the rewards for that period (5 days). However, since the user did not hold tokens during that time, the reward time should not be calculated.
Open the reportAfter transferring tokens to the pair, the following logic can be used to mark the `from` address as `_lastMaybeAddLPAddress` and the amount as `_lastMaybeAddLPAmount`: `nut_live.sol` ```solidity=639 if (from != address(this)) { if (to == mainPair) { _lastMaybeAddLPAddress = from; _lastMaybeAddLPAmount = amount; } ``` However, by transferring a certain amount of LP tokens to the `from` address before the next transfer, this sell token transaction can be misidentified as an add liquidity transaction, and the `from` address will be added to the `lpProviders` array to be eligible for rewards, even though the user did not actually add liquidity: `nut_live.sol` ```solidity=540 if (lastMaybeAddLPAddress != address(0)) { _lastMaybeAddLPAddress = address(0); uint256 lpBalance = IERC20(mainPair).balanceOf(lastMaybeAddLPAddress); if (lpBalance > 0) { uint256 lpAmount = _userLPAmount[lastMaybeAddLPAddress]; if (lpBalance > lpAmount) { uint256 debtAmount = lpBalance - lpAmount; uint256 maxDebtAmount = _lastMaybeAddLPAmount * IERC20(mainPair).totalSupply().div(_balances[mainPair]); if (debtAmount > maxDebtAmount) { excludeLpProvider[lastMaybeAddLPAddress] = true; } else { _addLpProvider(lastMaybeAddLPAddress); _userLPAmount[lastMaybeAddLPAddress] = lpBalance; uint256 blockTime = block.timestamp; if (0 == _lastLPRewardTimes[lastMaybeAddLPAddress]) { _lastLPRewardTimes[lastMaybeAddLPAddress] = blockTime; } } } } ``` This will introduce a security risk to the contract.
Open the reportFirst, the time for calculating staking reward after the user adds liquidity is not the time of addition, but rather the next transfer: `nut_live.sol` ```solidity=540 if (lastMaybeAddLPAddress != address(0)) { _lastMaybeAddLPAddress = address(0); uint256 lpBalance = IERC20(mainPair).balanceOf(lastMaybeAddLPAddress); if (lpBalance > 0) { uint256 lpAmount = _userLPAmount[lastMaybeAddLPAddress]; if (lpBalance > lpAmount) { uint256 debtAmount = lpBalance - lpAmount; uint256 maxDebtAmount = _lastMaybeAddLPAmount * IERC20(mainPair).totalSupply().div(_balances[mainPair]); if (debtAmount > maxDebtAmount) { excludeLpProvider[lastMaybeAddLPAddress] = true; } else { _addLpProvider(lastMaybeAddLPAddress); _userLPAmount[lastMaybeAddLPAddress] = lpBalance; uint256 blockTime = block.timestamp; if (0 == _lastLPRewardTimes[lastMaybeAddLPAddress]) { _lastLPRewardTimes[lastMaybeAddLPAddress] = blockTime; } } } } } ``` At the time when the user is supposed to receive rewards, not all the rewards accumulated during this period are distributed to the user and inviter; only the rewards for a 5-day period are distributed: `nut_live.sol` ```solidity=870 if (userUSDTContribution >= lpHoldCondition && block.timestamp > _lastLPRewardTimes[shareHolder] + lpRewardTimeDebt) { // Calculate 0.8% daily reward in USDT, then convert to NUT using pool price uint256 dailyUsdtReward = (userUSDTContribution.mul(DAILY_REWARD_RATE)).div(1000); uint256 rewardAmountInNUT = (dailyUsdtReward.mul(rNut)).div(rUsdt); rewardAmountInNUT *= 2; // Calculate total reward for the 5-day interval rewardAmount = rewardAmountInNUT.mul(5); if (rewardAmount > 0) { _lastLPRewardTimes[shareHolder] = block.timestamp; processInviterRewards(shareHolder, rewardAmount); _rewardTransfer(shareHolder, rewardAmount); } } ``` As a result, the rewards for the excess time will not be included in the calculation. Additionally, an attacker can increase the length of the LP provider array by mint small amounts of LP with multiple addresses in the main pair. This would delay the user's turn to receive the staking rewards, resulting in further staking reward losses.
Open the reportThe call to `_transfer()` of `AbsToken` is overcomplicated, involving dozens of logic, and some actions are performed on different levels.
Open the reportDuring a flash loan in the pair, when repaying NUT tokens, the `autoBurnLiquidityPairTokens` function may automatically burn tokens in the pair. In this case, since both the `swap` and `sync` functions of the pair have reentrancy locks, the transaction will revert when executing `mainPair.sync()`, causing the transaction to fail.
Open the reportThere should always be events emitted in the sensitive functions that are controlled by centralization roles.
Open the reportIf the value of `gasleft()` outside the `while` loop is less than the passed parameter `gas`, the `while` loop may throw an `out-of-gas` exception. ``` solidity=126 while (gasUsed < gas && iterations < shareholderCount) { if (currentIndex >= shareholderCount) { currentIndex = 0; } if (shouldDistribute(shareholders[currentIndex])) { distributeDividend(shareholders[currentIndex]); } gasUsed = gasUsed.add(gasLeft.sub(gasleft())); gasLeft = gasleft(); currentIndex++; iterations++; } ```
Open the reportA sandwich attack can occur when an attacker notices a transaction involving token swaps or liquidity additions that lacks slippage restrictions or minimum output amount settings. The attacker can exploit this by frontrunning the transaction to purchase one of the assets, thereby manipulating the exchange rate, and then backrunning the transaction to sell the asset for a profit. The referenced functions are invoked without setting slippage restrictions or minimum output amounts, making transactions that trigger these functions particularly vulnerable to sandwich attacks, especially when large input amounts are involved.
Open the reportThe contract is serving as the underlying entity to interact with one or more third party protocols. The scope of the audit treats third party entities as black boxes and assume their functional correctness. However, in the real world, third parties can be compromised and this may lead to lost or stolen assets. In addition, upgrades of third parties can possibly create severe impacts, such as increasing fees of third parties, migrating to new LP pools, etc. ```solidity=391 ISwapRouter public immutable _swapRouter; ``` - The contract `AbsToken` interacts with third party contract with `ISwapRouter` interface via `_swapRouter`. --- ```solidity=392 address public immutable _mainPair; ``` - The contract `AbsToken` interacts with third party contract with `ISwapPair` interface via `_mainPair`.
Open the report| Address | Chain | Source code |
|---|---|---|
| 0x29fd…978d0x29fdf61b4ab5a4af38c745d4e1ef282525d4978d | Chain: BNB Chain | Source code: Verified source |
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="nut-defi"></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