Equilibrium Quantum

CertiKFiles named in the report

CertiK reviewed Equilibrium Quantum on 18 Sep 2024: 24 findings, 0 critical; 2 marked fixed, 22 open.

No open critical findings
Open Equilibrium Quantum’s security record

The original report was removed from its address (seen 15 Oct 2026).

Trustblock does not review code.

Findings24

Statuses are the security firm’s own, from its report.

SeverityOpenAcknowledgedFixed
Critical000
High300
Medium100
Low1802
HighCentralization Related RisksOpen

In the contract `EQ`, the role `_owner` has authority over the functions below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority. - setTGAddress(): set the `tgAddress`. - excludeFromFee(): add the specified address into the `_isExcludedFromFee` list. - includeInFee(): remove the specified address from the `_isExcludedFromFee` list. - setTaxAddress(): set the address that received fees. - setTax(): set the tax ratio. - sweep(): claim the specified token from the contract. - renounceOwnership(): transfer the ownership to zero address. - transferOwnership(): transfer the ownership to the specified address. --- In the contract `EQTokenGuard`, the role `_owner` has authority over the functions below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority. - addBlackList(): add the specified address to the blacklist. - removeBlackList(): remove the specified address from the blacklist. - setLimit(): set the maximum amount limit per transaction. - renounceOwnership(): transfer the ownership to zero address. - transferOwnership(): transfer the ownership to the specified address. --- In the contract `LPPool`, the role `_owner` has authority over the functions below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority. - setTokenAddress(): set the reward token address. - setLPTokenAddress(): set the stake token address. - transferOwnership(): transfer the ownership to the specified address. --- In the contract `EQNFT`, the role `_owner` has authority over the functions below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority. - setMint(): add or remove the specified account to the `mintAddress`. - setBaseURI(): set the base URI of the NFT. - renounceOwnership(): transfer the ownership to zero address. - transferOwnership(): transfer the ownership to the specified address. In the contract `EQNFT`, the role `mintAddress` has authority over the functions below. Any compromise to the `mintAddress` account may allow the hacker to take advantage of this authority. - mint(): mint NFT to the specified account. --- In the contract `NodePool`, the role `_owner` has authority over the functions below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority. - setTokenAddress(): set the reward token address. - transferOwnership(): transfer the ownership to the specified address. --- In the contract `Sign`, the role `_owner` has authority over the functions below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority. - setVerifyAddress(): set the signer account. - setUserNonceAddress(): set the `UserNonce` contract address. - transferOwnership(): transfer the ownership to the specified address. In the contract `Sign`, the role `allowContract` has authority over the functions below. Any compromise to the `allowContract` account may allow the hacker to take advantage of this authority. - checkSign(): check the validity of the signature. --- In the contract `Store`, the role `_owner` has authority over the functions below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority. - setTokenAddress(): set the address of the purchased token. - setUsdtTokenAddress(): set the address of the payment token. - setNFTTokenAddress(): set the address of the purchased NFT token. - setAdminAddress(): set `adminAddress` to receive tokens from users' NFT purchases. - setAdminTransferAddress(): set `adminTransferAddress` to receive tokens from users' NFT purchases. - setBuyGasAllocRatio(): set the allocation ratio for each account when users purchase tokens. - setBuyGasAllocAddress(): set the allocation address for each account when users purchase tokens. - setBuyNFTUsdtAmount(): set the amount of `usdtToken` corresponding to each NFT. - setBuyNFTUsdtAllocAdminRatio(): set the `usdtToken` ratio received by the `adminAddress` account when users purchase NFTs. - transferOwnership(): transfer the ownership to the specified address. --- In the contract `UserNonce`, the role `_owner` has authority over the functions below. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority. - setLockBlock(): set the block interval for the nonce increment. - setUserNonce(): set the nonce of the specified account. - setUserLastBlock(): set the block number when the user last updated the nonce. - transferOwnership(): transfer the ownership to the specified address. In the contract `UserNonce`, the role `allowContract` has authority over the functions below. Any compromise to the `allowContract` account may allow the hacker to take advantage of this authority. - getAndIncrementUserNonce(): increase the user's nonce. --- In the contract `AllowContract`, the role `_owner` has authority over the functions below. Any c

HighInitial Token DistributionOpen

All of the **EQ** tokens are sent to the contract deployer or one or several externally-owned account (EOA) addresses. This is a centralization risk because the deployer or the owner(s) of the EOAs can distribute tokens without obtaining the consensus of the community. Any compromise to these addresses may allow a hacker to steal and sell tokens on the market, resulting in severe damage to the project.

HighWithdrawal Centralization RiskOpen

The `LPPool` contract enables users to stake their `LP` tokens to earn rewards. Users deposit their `LP` tokens into the `LPPool` contract and then wait for the project team to generate the necessary signatures for claiming rewards. It is important to note that rewards must be manually transferred to the contract. Users can unstake their `LP` tokens using the `unDepositLP()` function, but only after obtaining signatures from the project team. If the signer's private key is compromised, users' `LP` tokens may be at risk, potentially leading to losses for the users. Additionally, the owner of the contract has ability to withdraw `ERC20` tokens and native tokens through the `ownerSweep()` and `ownerWithdraw()` functions. If the owner's private key is compromised, users' `LP` tokens may be at risk, potentially leading to losses for the users.

MediumPotential Reentrancy AttackOpen

A reentrancy attack can occur when the contract creates a function that makes an external call to another untrusted contract before resolving any effects. If the attacker can control the untrusted contract, they can make a recursive call back to the original function, repeating interactions that would have otherwise not run after the external call resolved the effects.

LowBlock Timestamp Used As Deadline Parameter In UniOpen

In the Uniswap AMM system, a deadline is typically set for token swaps to prevent transactions from being executed after a certain amount of time, which could result in unfavorable price slippage. However, in the current contract, when conducting transactions using the Uniswap function, the deadline is set to `block.timestamp`, meaning "the deadline check will pass whatever block the transaction is in". If bots and maximal extractable value (MEV) strategies are widely used, it could affect many transactions. A malicious miner can hold the transaction as he wants to incur the maximum loss is reached. Therefore, the absence or incorrect usage of a deadline could make transactions more susceptible to front-running / MEV attacks, leading to greater price slippage losses.

LowClarification on `buyGas()`Open

In the `Store` contract, users can purchase `EQ` tokens using `USDT` tokens. The `buyGas()` function swaps `USDT` for `EQ` tokens on **PancakeSwap** and then distributes the tokens according to predefined ratios to the user, the team, the technical operations team, and a burn address. As a result, users may not receive 100% of the swapped `EQ` tokens.

LowClarification on Fee ExclusionOpen

In the `_transfer()` function, if the `sender` is excluded from fees, then the transaction is fee-free. ```solidity if (_isExcludedFromFee[sender]) { takeFee = false; } ``` However, the function does not check if `recipient` is excluded from fees.

LowIncompatibility With Deflationary Tokens (Non-staOpen

The project design may not be compatible with non-standard ERC20 tokens, such as deflationary tokens or rebase tokens. The functions use `transferFrom()`/`transfer()` to move funds from the sender to the recipient but fail to verify if the received token amount matches the transferred amount. This could pose an issue with fee-on-transfer tokens, where the post-transfer balance might be less than anticipated, leading to balance inconsistencies. There might be subsequent checks for a second transfer, but an attacker might exploit leftover funds (such as those accidentally sent by another user) to gain unjustified credit.

LowMeaningless FunctionOpen

Due to the absence of a `receive()` function in the `BaseContract` and its derived contracts, as well as the lack of the `payable` keyword with the contract functions, the contract cannot accept native token transfers. Therefore, the aforementioned functions are meaningless. ```solidity function getBalance() public view returns(uint256) { return address(this).balance; } function ownerWithdraw() public onlyOwner { uint256 b = address(this).balance; require(b > 0, "insufficient balance."); payable(owner()).transfer(b); } ```

LowMissing checks for `ecrecover()` signature malleaOpen

The `ecrecover()` function accepts two versions of signatures as valid. This vulnerability allows an attacker to use the same signature twice or potentially front-run the original signer with an altered version of the signature. Consequently, the signer's transaction could revert due to nonce reuse. References: [***Signature Malleability***](https://medium.com/draftkings-engineering/signature-malleability-7a804429b14a)

Show 10 more
LowMissing Emit EventsOpen

The smart contract contains one or more state changes related to access control that do not emit events to communicate the changes outside the blockchain, which can lead to difficulties in tracking or verifying these changes and may affect the contract's transparency and auditability.

LowMissing Zero Address ValidationOpen

Addresses are not validated before assignment or external calls, potentially allowing the use of zero addresses and leading to unexpected behavior or vulnerabilities. For example, transferring tokens to a zero address can result in a permanent loss of those tokens.

LowNo Cap on FeesOpen

The `dexTaxFee` variables in the contract have no set limits, allowing fees to potentially reach 100%. If this occurs, users would receive no tokens from the contract, resulting in a complete loss of their investment.

LowOpposite Function Modifier NamingOpen

The modifier name `isPaused` suggests that the contract should be paused, but it actually requires the contract to be unpaused. This creates confusion and makes the code harder to understand and maintain.

LowPotential Cross-Chain Replay AttackOpen

Signed messages are not properly verified with the current chain ID, thus allowing attackers to perform replay attacks across chains. Hardcoded or cached chain ID values are also vulnerable since a hard fork may occur and change the chain ID in the future.

LowPotential Loss of PrecisionOpen

The `buyGas()` function is responsible for distributing tokens that users have purchased. However, there is a potential precision loss issue when calculating related values by multiplying each ratio. ```solidity allocTokenAmountList[0] = (tokenAmount * buyGasAllocRatioList[1]) / 10000; allocTokenAmountList[1] = (tokenAmount * buyGasAllocRatioList[2]) / 10000; allocTokenAmountList[2] = (tokenAmount * buyGasAllocRatioList[3]) / 10000; allocTokenAmountList[3] = (tokenAmount * buyGasAllocRatioList[4]) / 10000; ``` This can lead to a small amount of tokens being locked in the contract.

LowPotential Replay Attack Caused By Using `abi.encoOpen

As a general practice, use of `abi.encodePacked` isn't recommended, since it is susceptible to hash collisions in some instances where dynamically-sized inputs are used consecutively. For example, in the `Sign` contract, the signature verification process utilizes `abi.encodePacked` to encode multiple dynamic-length variables. This practice can lead to hash collisions, which can be exploited to perform replay attacks. The relevant code is shown below: ```solidity keccak256( abi.encodePacked( _contractAddress, _toAddress, _funcName, _seed.sSeed, _nonce, _seed.flag, _messageHash ) ); ``` When `abi.encodePacked` is used with dynamic-length variables, it can produce the same output for different sets of inputs, causing a potential vulnerability. An attacker could exploit this by crafting inputs that result in the same hash, allowing them to reuse a valid signature to exploit.

LowPotential Sandwich AttacksOpen

A 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.

LowRedundant CheckOpen

The `has()` function is designed to check if the input parameter `_addr` is in the `contractList`. However, it includes a check that requires `_addr` to already be in `contractList`. In the `BaseContract` contract, the modifier `isAllowContract()` calls the `has()` function to determine whether to revert. Thus, the `require()` check within the `has()` function is redundant. --- In the `getAndIncrementUserNonce()` function, there are two validations for when `_lastBlock` is greater than zero. One requires that `block.number` is at least `_lastBlock`, while the other requires that `block.number` is at least `_lastBlock + lockBlock`. Since the second validation inherently ensures the first condition is met, the first `require()` check is redundant.

LowState Variable Should Be Declared ConstantOpen

State variables that never change should be declared as `constant` to save gas. ```solidity=505 uint256 private _initSupply = 21000000 * 10**18; ``` - `_initSupply` should be declared `constant`. ```solidity=504 string private _symbol = "EQ"; ``` - `_symbol` should be declared `constant`. ```solidity=503 string private _name = "EQ"; ``` - `_name` should be declared `constant`.

Show 2 more
LowThird-Party Dependency UsageOpen

The 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 assumes 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 IPancakeRouter02 public immutable pancakeRouter; address public tokenAddress; address public usdtTokenAddress; address public nftTokenAddress; ``` - The contract `Store` interacts with the above third party contracts. ```solidity address public immutable pairAddress; address public immutable routerAddress; address public usdtAddress; ``` - The contract `EQToken` interacts with the above third party contracts. ```solidity address public tokenAddress; address public lpTokenAddress; ``` - The contract `LPPool` interacts with the above third party contracts. ```solidity address public tokenAddress; ``` - The contract `NodePool` interacts with the above third party contracts.

LowUnused Return ValueOpen

The smart contract does not check or store the return value of an external call in a local or state variable, which may introduce vulnerabilities due to the unhandled outcome.

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (5)

  • EQToken.sol
  • EQNFT.sol
  • BaseContract.sol
  • AllowContract.sol
  • EQTokenGuard.sol

Part of Equilibrium Quantum’s security record

Equilibrium Quantum
Audits2 audits by 1 firmLast audit Nov 2024, by CertiK.
Critical findingsNo open critical findingsAcross 2 reports.
Open Equilibrium Quantum’s security record

Security firm

CertiK

1,044 projects reviewed · 1,375 reports · latest May 2025

See CertiK’s audits

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