> For the complete documentation index, see [llms.txt](https://audits.solidgrp.io/ethernity/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://audits.solidgrp.io/ethernity/audit-results/findings.md).

# Findings

## **Issue 01**

| **Type**           | **Severity**                             | **Location**    | **Status**                                        |
| ------------------ | ---------------------------------------- | --------------- | ------------------------------------------------- |
| Owner Capabilities | <mark style="color:red;">**High**</mark> | `withdrawERC20` | ✔️ <mark style="color:green;">**Resolved**</mark> |

**Description**

The owner of the contract can withdraw users' staked tokens at any time.

**Recommendation**

If the purpose of this function is to withdraw tokens accidentally sent to the contract, consider adding a require statement that makes sure the withdrawn token by the owner is not the native token. If it is the native token, add a variable that tracks the tokens staked and stops the owner with withdrawing them.

<mark style="color:yellow;">**Second Revision**</mark>

The owner of the contract can modify the token address, and therefore can still withdraw any token.

## **Issue 02**

| **Type**         | **Severity**                                        | **Location** | **Status**                                        |
| ---------------- | --------------------------------------------------- | ------------ | ------------------------------------------------- |
| Gas Optimization | <mark style="color:green;">**Informational**</mark> | `receive`    | ✔️ <mark style="color:green;">**Resolved**</mark> |

**Description**

By default, ETH can't be sent to smart contracts unless they have a receive function.

**Recommendation**

Consider removing the receive function as it's not necessary.&#x20;

## **Issue 03**

| **Type**      | **Severity**                             | **Location**         | **Status**                                        |
| ------------- | ---------------------------------------- | -------------------- | ------------------------------------------------- |
| Volatile Code | <mark style="color:red;">**High**</mark> | `deposit / fundPool` | ✔️ <mark style="color:green;">**Resolved**</mark> |

**Description**

`transferFrom` function can silently fail without being reverted.

**Recommendation**

Use safeTransferFrom or check the return value of the transferFrom function.

## **Issue 04**

| **Type**      | **Severity**                                  | **Location** | **Status**                                        |
| ------------- | --------------------------------------------- | ------------ | ------------------------------------------------- |
| Logical Issue | <mark style="color:orange;">**Medium**</mark> | `withdraw`   | ✔️ <mark style="color:green;">**Resolved**</mark> |

**Description**

The following line can trigger a math underflow if mainPen (that is based on the staked amount) is larger than the reward

```
uint256 totalReward = (reward - (mainPen + subPen));
```

## **Issue 05**

| **Type**      | **Severity**                                        | **Location**        | **Status**                                        |
| ------------- | --------------------------------------------------- | ------------------- | ------------------------------------------------- |
| Logical Issue | <mark style="color:green;">**Informational**</mark> | `emergancyWithdraw` | ✔️ <mark style="color:green;">**Resolved**</mark> |

**Description**

In emergencyWithdraw function, stakedAmount is not decreased.

## **Issue 06**

| **Type**      | **Severity**                                  | **Location**   | **Status**                                        |
| ------------- | --------------------------------------------- | -------------- | ------------------------------------------------- |
| Logical Issue | <mark style="color:orange;">**Medium**</mark> | `calculateRew` | ✔️ <mark style="color:green;">**Resolved**</mark> |

According to the docs if&#x20;

```
* | apy = 10000000000000000000=> %10 Monthly
```

The equation for calculating the rewards is wrong.

## **Issue 07**

| **Type**      | **Severity**                               | **Location**   | **Status**                                                                                                                      |
| ------------- | ------------------------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Best Practice | <mark style="color:yellow;">**Low**</mark> | `calculateRew` | <mark style="color:red;">**❌**</mark><mark style="color:red;">**&#x20;**</mark><mark style="color:red;">**Not Resolved**</mark> |

**Description**

Penalty and APY percentages use a 1e18 multiplier, that allows for extremely high precision. However, it is customary to use a lower multiplier like 100 or 1,000, to minimize the risk of human error.

**Recommendation**

We suggest reducing the 1e18 multiplier to 1,000, which provides a precision of up to 0.1%

## **Issue 08**

| **Type**      | **Severity**                               | **Location**                                                 | **Status**                                                                                                                      |
| ------------- | ------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| Best Practice | <mark style="color:yellow;">**Low**</mark> | `calculateFutureRew / calculateRewFromAmount / calculateRew` | <mark style="color:red;">**❌**</mark><mark style="color:red;">**&#x20;**</mark><mark style="color:red;">**Not Resolved**</mark> |

**Description**

It is bad practice to duplicate core functionality of the code (e.g. APY calculation).

**Recommendation**

Use only one function that calculates the APY and calls it with the appropriate parameters every time.

We recommend using one calculate APY function that receives:

amount, apy, duration.

## **Issue 09**

| **Type**      | **Severity**                             | **Location**   | **Status**                                        |
| ------------- | ---------------------------------------- | -------------- | ------------------------------------------------- |
| Logical Issue | <mark style="color:red;">**High**</mark> | `claimPending` | ✔️ <mark style="color:green;">**Resolved**</mark> |

**Description**

If a pool has no mainPenalty, mainAmount will be 0 which means the user won't be able to withdraw his original staked amount.

## General Notes

* Consider adding an emergency withdrawal function that would let the user simply withdraw his staked tokens without doing extra logic, even if the token is paused. Note that if this suggestion is accepted, it may allow users to avoid penalties by calling emergencyWithdraw - The team has decided to enable emergency withdrawals only when the staking contract is paused.&#x20;
* isFinished modifier checks if the staker status is not finished, consider renaming the function to reflect this logic.&#x20;
* The code does not support a token with transfer fees - staker.amount and the reserves of the pool may not be correct which will every function that withdraws it.&#x20;
