Biconomy Hyphen 2.0 contest - IllIllI's results

Next-Gen Multichain Relayer Protocol.

General Information

Platform: Code4rena

Start Date: 10/03/2022

Pot Size: $75,000 USDT

Total HM: 25

Participants: 54

Period: 7 days

Judge: pauliax

Total Solo HM: 10

Id: 97

League: ETH

Biconomy

Findings Distribution

Researcher Performance

Rank: 19/54

Findings: 4

Award: $730.31

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: Jujic

Also found by: IllIllI, Ruhum, defsec, hagrid, minhquanym, shenwilly

Labels

bug
duplicate
2 (Med Risk)

Awards

99.257 USDT - $99.26

External Links

Lines of code

https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityPool.sol#L170 https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityPool.sol#L293 https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityPool.sol#L379 https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityPool.sol#L407

Vulnerability details

Some ERC20 tokens, such as USDT, allow for charging a fee any time transfer() or transferFrom() is called. If a contract does not allow for amounts to change after transfers, subsequent transfer operations based on the original amount will revert() due to the contract having an insufficient balance.

Impact

The current implementation does not work properly with fee-on-transfer tokens when calling transfer()/transferFrom()

Proof of Concept

The following calls are separate instances of this issue where the call may suddenly start reverting for a fee-on-transfer token when the fee is turned on right before the function call, or has been on prior to the call:

        SafeERC20Upgradeable.safeTransferFrom(IERC20Upgradeable(tokenAddress), sender, address(this), amount);

https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityPool.sol#L170

            SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(tokenAddress), receiver, amountToTransfer);

https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityPool.sol#L293

        SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(tokenAddress), _msgSender(), _gasFeeAccumulated);

https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityPool.sol#L379

            SafeERC20Upgradeable.safeTransfer(baseToken, receiver, _tokenAmount);

https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityPool.sol#L407

Tools Used

Code inspection

One way to work around the issue is to measure the contract's balance right before and after the asset-transferring functions, and using the difference rather than the stated transferred amount.

#0 - ankurdubey521

2022-03-30T15:49:00Z

Duplicate of #39

Findings Information

🌟 Selected for report: throttle

Also found by: IllIllI, Ruhum, cccz, cmichel, danb, pedroais

Labels

bug
duplicate
2 (Med Risk)
sponsor acknowledged

Awards

99.257 USDT - $99.26

External Links

Lines of code

https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityProviders.sol#L116-L118 https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityProviders.sol#L148-L150 https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityProviders.sol#L317-L327

Vulnerability details

Impact

By implementing malicious versions of the interfaces required by the contracts used in the set*() functions, an owner can rug pull user positions.

Even if the owner is benevolent the fact that there is a rug vector available may negatively impact the protocol's reputation. See these examples where similar findings have been flagged as a high-severity issues.

Proof of Concept

In a single transaction, the owner can transfer ownership to another contract that calls LiquidityProviders.setLpToken() and LiquidityProviders.setTokenManager() with malicious versions...

    function setLpToken(address _lpToken) external onlyOwner {
        _setLPToken(_lpToken);
    }

https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityProviders.sol#L116-L118

    function setTokenManager(address _tokenManager) external onlyOwner {
        _setTokenManager(_tokenManager);
    }

https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityProviders.sol#L148-L150

..and calls LiquidityProviders.increaseTokenLiquidity() with a large _amount...

...where lpToken.tokenMetadata() returns an address of a token that has a supply controled by the owner and is accepted by the tokenManager and which changes the lpToken back to the original (there is no nonReentrant modifier on the set functions) after safeTransferFrom() is called, and changes the ownership back...

    function increaseTokenLiquidity(uint256 _nftId, uint256 _amount) external nonReentrant whenNotPaused {
        (address token, , ) = lpToken.tokenMetadata(_nftId);
        require(_isSupportedToken(token), "ERR__TOKEN_NOT_SUPPORTED");
        require(token != NATIVE, "ERR__WRONG_FUNCTION");
        require(
            IERC20Upgradeable(token).allowance(_msgSender(), address(this)) >= _amount,
            "ERR__INSUFFICIENT_ALLOWANCE"
        );
        SafeERC20Upgradeable.safeTransferFrom(IERC20Upgradeable(token), _msgSender(), address(liquidityPool), _amount);
        _increaseLiquidity(_nftId, _amount);
    }

https://github.com/code-423n4/2022-03-biconomy/blob/04751283f85c9fc94fb644ff2b489ec339cd9ffc/contracts/hyphen/LiquidityProviders.sol#L317-L327

...so that _increaseLiquidity() gives the owner arbitrary amounts. The owner can then have the contract call LiquidityProviders.removeLiquidity() to withdraw.

Alternative scenarios include:

  • making lpToken.tokenMetadata() return incorrect amounts, leading to the contract's accounting breaking
  • bricking the system by setting 0x00 as the various addresses for the various set*() functions of the various contracts
  • setting an absurdly large value for baseGas

Tools Used

Code inspection

Don't allow the owner to change contract addresses of existing pools; require old pools to be indefinitely paused and new ones to be started.

#0 - ankurdubey521

2022-03-30T10:27:05Z

I agree this is an issue, but in the current iteration of Hyphen it is still a centralized system, therefore there is an implicit trust in the contract owners and executors. A decentralized version of the Hyphen bridge is in the works and will fix these issues.

Awards

182.6856 USDT - $182.69

Labels

bug
QA (Quality Assurance)

External Links

Low-impact Issues

setTotalCap() should require that areWhiteListRestrictionsEnabled is true

  1. File: contracts/hyphen/WhitelistPeriodManager.sol (lines 186-193)
    function setTotalCap(address _token, uint256 _totalCap) public tokenChecks(_token) onlyOwner {
        require(totalLiquidity[_token] <= _totalCap, "ERR__TOTAL_CAP_LESS_THAN_SL");
        require(_totalCap >= perTokenWalletCap[_token], "ERR__TOTAL_CAP_LT_PTWC");
        if (perTokenTotalCap[_token] != _totalCap) {
            perTokenTotalCap[_token] = _totalCap;
            emit TotalCapUpdated(_token, _totalCap);
        }
    }

The current total may be N, and the cap may be set to N+X. Since areWhiteListRestrictionsEnabled is not forced to be true, users may push the total to N+X+Y, and when the restriction is enabled, the total will already be over the limit.

Upgradeable contract is missing a __gap[50] storage variable to allow for new storage variables in later versions

See this link for a description of this storage variable. While some contracts may not currently be sub-classed, adding the variable now protects against forgetting to add it in the future.

  1. File: contracts/hyphen/proxy/LiquidityPoolProxy.sol (line 29)
contract LiquidityPoolProxy is TransparentUpgradeableProxy {
  1. File: contracts/hyphen/token/LPToken.sol (lines 17-23)
contract LPToken is
    OwnableUpgradeable,
    ReentrancyGuardUpgradeable,
    ERC721EnumerableUpgradeable,
    ERC721URIStorageUpgradeable,
    ERC2771ContextUpgradeable,
    Pausable
  1. File: contracts/hyphen/LiquidityFarming.sol (lines 16-22)
contract HyphenLiquidityFarming is
    Initializable,
    ERC2771ContextUpgradeable,
    OwnableUpgradeable,
    Pausable,
    ReentrancyGuardUpgradeable,
    IERC721ReceiverUpgradeable
  1. File: contracts/hyphen/LiquidityPool.sol (line 18)
contract LiquidityPool is ReentrancyGuardUpgradeable, Pausable, OwnableUpgradeable, ERC2771ContextUpgradeable {
  1. File: contracts/hyphen/LiquidityProviders.sol (lines 17-22)
contract LiquidityProviders is
    Initializable,
    ReentrancyGuardUpgradeable,
    ERC2771ContextUpgradeable,
    OwnableUpgradeable,
    Pausable
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 15)
contract WhitelistPeriodManager is Initializable, OwnableUpgradeable, Pausable, ERC2771ContextUpgradeable {

getAllNftIdsByUser() should take in a beginning and ending index to avoid running out of gas due to calls to tokenOfOwnerByIndex()

  1. File: contracts/hyphen/token/LPToken.sol (line 75)
    function getAllNftIdsByUser(address _owner) public view returns (uint256[] memory) {

LPToken should be defined as is ILPToken to avoid function signature mistakes leading to incompatibility

  1. File: contracts/hyphen/token/LPToken.sol (lines 17-24)
contract LPToken is
    OwnableUpgradeable,
    ReentrancyGuardUpgradeable,
    ERC721EnumerableUpgradeable,
    ERC721URIStorageUpgradeable,
    ERC2771ContextUpgradeable,
    Pausable
{

NATIVE should be an address guaranteed to not match an address a user may use

It's safer to use 0x00 as the native address, since that's what solidity itself does. A user may happen to create a contract or EOA with the current value.

  1. File: contracts/hyphen/LiquidityFarming.sol (line 68)
    address internal constant NATIVE = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

Non-critical Issues

State variables written after external calls

The best-practice is to follow the check-effects-interactions pattern

  1. File: contracts/hyphen/LiquidityFarming.sol (line 244)
        delete nftInfo[_nftId];
  1. File: contracts/hyphen/LiquidityFarming.sol (line 248)
        totalSharesStaked[baseToken] -= amount;

Typos

  1. File: contracts/hyphen/LiquidityFarming.sol (line 178)
    /// reightful owner of the extra tokens, and ether, protector of mistaken transfers, mother of token reclaimers,
  1. File: contracts/hyphen/LiquidityPool.sol (line 300)
     * @dev Internal function to calculate amount of token that needs to be transfered afetr deducting all required fees.

Two instances of the same contract name in the same project

  1. File: contracts/hyphen/metatx/ERC2771ContextUpgradeable.sol (line 13)
abstract contract ERC2771ContextUpgradeable is Initializable, ContextUpgradeable {

and node_modules/@openzeppelin/contracts-upgradeable/metatx/ERC2771ContextUpgradeable.sol

  1. File: (line 17)
abstract contract Pausable is Initializable, PausableUpgradeable {

and node_modules/@openzeppelin/contracts/security/Pausable.sol

Multiple address mappings should be combined into a single mapping of an address to a struct, where appropriate

  1. File: contracts/hyphen/LiquidityFarming.sol (lines 56-65)
    mapping(address => address) public rewardTokens;

    /// @notice Staker => NFTs staked
    mapping(address => uint256[]) public nftIdsStaked;

    /// @notice Token => Total Shares Staked
    mapping(address => uint256) public totalSharesStaked;

    /// @notice Token => Reward Rate Updation history
    mapping(address => RewardsPerSecondEntry[]) public rewardRateLog;
  1. File: contracts/hyphen/LiquidityPool.sol (lines 38-44)
    mapping(address => uint256) public gasFeeAccumulatedByToken;

    // Gas fee accumulated by token address => executor address
    mapping(address => mapping(address => uint256)) public gasFeeAccumulated;

    // Incentive Pool amount per token address
    mapping(address => uint256) public incentivePool;
  1. File: contracts/hyphen/LiquidityProviders.sol (lines 42-46)
    mapping(address => uint256) public totalReserve; // Include Liquidity + Fee accumulated
    mapping(address => uint256) public totalLiquidity; // Include Liquidity only
    mapping(address => uint256) public currentLiquidity; // Include current liquidity, updated on every in and out transfer
    mapping(address => uint256) public totalLPFees;
    mapping(address => uint256) public totalSharesMinted;
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (lines 23-33)
    mapping(address => bool) public isExcludedAddress;
    // Token -> TVL
    mapping(address => uint256) private totalLiquidity;
    // Token -> TVL
    mapping(address => mapping(address => uint256)) public totalLiquidityByLp;

    /* Caps */
    // Token Address -> Limit
    mapping(address => uint256) public perTokenTotalCap;
    // Token Address -> Limit
    mapping(address => uint256) public perTokenWalletCap;

Misleading variable/function names

  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 19)
    bool public areWhiteListRestrictionsEnabled;

This variable tracks whether the asset caps are enabled, not whether there's an allow-list. Consider renaming to areCapsEnabled

Use scientific notation (e.g. 10e18) rather than exponentiation (e.g. 10**18)

  1. File: contracts/hyphen/LiquidityProviders.sol (line 27)
    uint256 public constant BASE_DIVISOR = 10**18;

public functions not called by the contract should be declared external instead

Contracts are allowed to override their parents' functions and change the visibility from external to public.

  1. File: contracts/hyphen/token/LPToken.sol (line 56)
    function setSvgHelper(address _tokenAddress, ISvgHelper _svgHelper) public onlyOwner {
  1. File: contracts/hyphen/token/LPToken.sol (line 75)
    function getAllNftIdsByUser(address _owner) public view returns (uint256[] memory) {
  1. File: contracts/hyphen/token/LPToken.sol (line 98)
    function exists(uint256 _tokenId) public view returns (bool) {
  1. File: contracts/hyphen/token/TokenManager.sol (line 36)
    function getEquilibriumFee(address tokenAddress) public view override returns (uint256) {
  1. File: contracts/hyphen/token/TokenManager.sol (line 40)
    function getMaxFee(address tokenAddress) public view override returns (uint256) {
  1. File: contracts/hyphen/token/TokenManager.sol (line 115)
    function getTokensInfo(address tokenAddress) public view override returns (TokenInfo memory) {
  1. File: contracts/hyphen/token/TokenManager.sol (lines 126-130)
    function getDepositConfig(uint256 toChainId, address tokenAddress)
        public
        view
        override
        returns (TokenConfig memory)
  1. File: contracts/hyphen/token/TokenManager.sol (line 135)
    function getTransferConfig(address tokenAddress) public view override returns (TokenConfig memory) {
  1. File: contracts/hyphen/ExecutorManager.sol (line 21)
    function getExecutorStatus(address executor) public view override returns (bool status) {
  1. File: contracts/hyphen/ExecutorManager.sol (line 25)
    function getAllExecutors() public view override returns (address[] memory) {
  1. File: contracts/hyphen/LiquidityFarming.sol (line 169)
    function setRewardPerSecond(address _baseToken, uint256 _rewardPerSecond) public onlyOwner {
  1. File: contracts/hyphen/LiquidityFarming.sol (line 329)
    function getNftIdsStaked(address _user) public view returns (uint256[] memory nftIds) {
  1. File: contracts/hyphen/LiquidityFarming.sol (line 333)
    function getRewardRatePerSecond(address _baseToken) public view returns (uint256) {
  1. File: contracts/hyphen/LiquidityPool.sol (line 107)
    function setTrustedForwarder(address trustedForwarder) public onlyOwner {
  1. File: contracts/hyphen/LiquidityPool.sol (line 113)
    function setLiquidityProviders(address _liquidityProviders) public onlyOwner {
  1. File: contracts/hyphen/LiquidityPool.sol (line 123)
    function getExecutorManager() public view returns (address) {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 96)
    function getTotalReserveByToken(address tokenAddress) public view returns (uint256) {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 100)
    function getSuppliedLiquidityByToken(address tokenAddress) public view returns (uint256) {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 104)
    function getTotalLPFeeByToken(address tokenAddress) public view returns (uint256) {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 108)
    function getCurrentLiquidity(address tokenAddress) public view returns (uint256) {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 127)
    function increaseCurrentLiquidity(address tokenAddress, uint256 amount) public onlyLiquidityPool {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 131)
    function decreaseCurrentLiquidity(address tokenAddress, uint256 amount) public onlyLiquidityPool {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 201)
    function getFeeAccumulatedOnNft(uint256 _nftId) public view returns (uint256) {

Large multiples of ten should use scientific notation (e.g. 1e6) rather than decimal literals (e.g. 1000000), for readability

  1. File: contracts/hyphen/LiquidityPool.sol (line 20)
    uint256 private constant BASE_DIVISOR = 10000000000; // Basis Points * 100 for better accuracy
  1. File: contracts/hyphen/LiquidityPool.sol (line 184)
                rewardAmount = (amount * incentivePool[tokenAddress] * 10000000000) / liquidityDifference;
  1. File: contracts/hyphen/LiquidityPool.sol (line 185)
                rewardAmount = rewardAmount / 10000000000;

require()/revert() statements should have descriptive reason strings

  1. File: contracts/security/Pausable.sol (line 60)
        require(newPauser != address(0));

Inconsistent use of white space

The code is missing a space between if and its condition statement

  1. File: contracts/hyphen/LiquidityProviders.sol (line 214)
        if(nftSuppliedLiquidity > eligibleLiquidity) {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 366)
        if(nftSuppliedLiquidity > eligibleLiquidity) {

Consider adding timelocks and emitting events for functions that use the only*() modifiers

See this issue from a prior contest for details

  1. File: contracts/hyphen/token/TokenManager.sol (lines 44-48)
    function changeFee(
        address tokenAddress,
        uint256 _equilibriumFee,
        uint256 _maxFee
    ) external override onlyOwner whenNotPaused {
  1. File: contracts/hyphen/token/TokenManager.sol (lines 56-59)
    function setTokenTransferOverhead(address tokenAddress, uint256 gasOverhead)
        external
        tokenChecks(tokenAddress)
        onlyOwner
  1. File: contracts/hyphen/LiquidityFarming.sol (line 169)
    function setRewardPerSecond(address _baseToken, uint256 _rewardPerSecond) public onlyOwner {
  1. File: contracts/hyphen/LiquidityPool.sol (line 107)
    function setTrustedForwarder(address trustedForwarder) public onlyOwner {
  1. File: contracts/hyphen/LiquidityPool.sol (line 119)
    function setBaseGas(uint128 gas) external onlyOwner {
  1. File: contracts/hyphen/LiquidityPool.sol (line 127)
    function setExecutorManager(address _executorManagerAddress) external onlyOwner {
  1. File: contracts/hyphen/LiquidityPool.sol (lines 263-270)
    function sendFundsToUser(
        address tokenAddress,
        uint256 amount,
        address payable receiver,
        bytes memory depositHash,
        uint256 tokenGasPrice,
        uint256 fromChainId
    ) external nonReentrant onlyExecutor tokenChecks(tokenAddress) whenNotPaused {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 229)
    function addLPFee(address _token, uint256 _amount) external onlyLiquidityPool tokenChecks(_token) whenNotPaused {

Awards

349.1007 USDT - $349.10

Labels

bug
G (Gas Optimization)

External Links

Remove unused function calls and their return values

  1. File: contracts/hyphen/LiquidityProviders.sol (line 54)
        (address token, , ) = lpToken.tokenMetadata(_tokenId);

Expensive functions should be memoized

https://en.wikipedia.org/wiki/Memoization

  1. File: contracts/hyphen/token/LPToken.sol (lines 112-117)
    function tokenURI(uint256 tokenId)
        public
        view
        virtual
        override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
        returns (string memory)

Refactor state variables to get gas refunds

  1. File: contracts/hyphen/ExecutorManager.sol (lines 9-10
    address[] internal executors;
    mapping(address => bool) internal executorStatus;

By storing the index of the user in the executors array as the value for the executorStatus mapping, you can later delete the user from array using that index, which refunds gas

Refactor code to avoid duplicate checks

  1. File: contracts/hyphen/WhitelistPeriodManager.sol (lines 92-96)
        require(ifEnabled(totalLiquidity[_token] + _amount <= perTokenTotalCap[_token]), "ERR__LIQUIDITY_EXCEEDS_PTTC");
        require(
            ifEnabled(totalLiquidityByLp[_token][_lp] + _amount <= perTokenWalletCap[_token]),
            "ERR__LIQUIDITY_EXCEEDS_PTWC"
        );

Wrap the two require statements in two if-statement that uses the left-most conditions from inside ifEnabled(), to get rid of the duplicate calls to ifEnabled()

Use a more recent version of OpenZeppelin to gain gas efficiencies

See this issue from a prior contest for details

  1. File: package.json (line 41)
    "@openzeppelin/contracts": "4.3.0",

It costs more gas to initialize variables to zero than to let the default of zero be applied

  1. File: contracts/hyphen/token/LPToken.sol (line 77)
        for (uint256 i = 0; i < nftIds.length; ++i) {
  1. File: contracts/hyphen/token/svg-helpers/SvgHelperBase.sol (line 29)
        uint256 count = 0;
  1. File: contracts/hyphen/token/svg-helpers/SvgHelperBase.sol (line 45)
        for (uint256 i = 0; i < _length; ++i) {
  1. File: contracts/hyphen/token/svg-helpers/SvgHelperBase.sol (line 68)
        uint256 leadingZeroesToAddBeforeDecimal = 0;
  1. File: contracts/hyphen/token/TokenManager.sol (line 78)
        for (uint256 index = 0; index < tokenConfig.length; ++index) {
  1. File: contracts/hyphen/ExecutorManager.sol (line 31)
        for (uint256 i = 0; i < executorArray.length; ++i) {
  1. File: contracts/hyphen/ExecutorManager.sol (line 47)
        for (uint256 i = 0; i < executorArray.length; ++i) {
  1. File: contracts/hyphen/LiquidityFarming.sol (line 266)
        uint256 accumulator = 0;
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 180)
        for (uint256 i = 0; i < _addresses.length; ++i) {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 228)
        for (uint256 i = 0; i < _tokens.length; ++i) {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 247)
        uint256 maxLp = 0;

++i/i++ should be unchecked{++i}/unchecked{++i} when it is not possible for them to overflow, as is the case when used in for- and while-loops

  1. File: contracts/hyphen/token/LPToken.sol (line 77)
        for (uint256 i = 0; i < nftIds.length; ++i) {
  1. File: contracts/hyphen/token/svg-helpers/SvgHelperBase.sol (line 45)
        for (uint256 i = 0; i < _length; ++i) {
  1. File: contracts/hyphen/token/TokenManager.sol (line 78)
        for (uint256 index = 0; index < tokenConfig.length; ++index) {
  1. File: contracts/hyphen/ExecutorManager.sol (line 31)
        for (uint256 i = 0; i < executorArray.length; ++i) {
  1. File: contracts/hyphen/ExecutorManager.sol (line 47)
        for (uint256 i = 0; i < executorArray.length; ++i) {
  1. File: contracts/hyphen/LiquidityFarming.sol (line 233)
        for (index = 0; index < nftsStakedLength; ++index) {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 180)
        for (uint256 i = 0; i < _addresses.length; ++i) {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 228)
        for (uint256 i = 0; i < _tokens.length; ++i) {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 248)
        for (uint256 i = 1; i <= totalSupply; ++i) {

<array>.length should not be looked up in every loop of a for-loop

Even memory arrays incur the overhead of bit tests and bit shifts to calculate the array length

  1. File: contracts/hyphen/token/LPToken.sol (line 77)
        for (uint256 i = 0; i < nftIds.length; ++i) {
  1. File: contracts/hyphen/token/TokenManager.sol (line 78)
        for (uint256 index = 0; index < tokenConfig.length; ++index) {
  1. File: contracts/hyphen/ExecutorManager.sol (line 31)
        for (uint256 i = 0; i < executorArray.length; ++i) {
  1. File: contracts/hyphen/ExecutorManager.sol (line 47)
        for (uint256 i = 0; i < executorArray.length; ++i) {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 180)
        for (uint256 i = 0; i < _addresses.length; ++i) {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 228)
        for (uint256 i = 0; i < _tokens.length; ++i) {

Using calldata instead of memory for read-only arguments in external functions saves gas

  1. File: contracts/hyphen/token/LPToken.sol (line 89)
    function updateTokenMetadata(uint256 _tokenId, LpTokenMetadata memory _lpTokenMetadata)
  1. File: contracts/hyphen/token/TokenManager.sol (line 70)
        uint256[] memory toChainId,
  1. File: contracts/hyphen/token/TokenManager.sol (line 71)
        address[] memory tokenAddresses,
  1. File: contracts/hyphen/token/TokenManager.sol (line 72)
        TokenConfig[] memory tokenConfig
  1. File: contracts/hyphen/interfaces/ILiquidityPool.sol (line 13)
        bytes memory depositHash
  1. File: contracts/hyphen/interfaces/ILiquidityPool.sol (line 23)
        string memory tag
  1. File: contracts/hyphen/interfaces/ILiquidityPool.sol (line 29)
        string memory tag
  1. File: contracts/hyphen/interfaces/ILiquidityPool.sol (line 74)
        bytes memory depositHash,
  1. File: contracts/hyphen/interfaces/IWhiteListPeriodManager.sol (line 57)
        address[] memory _tokens,
  1. File: contracts/hyphen/interfaces/IWhiteListPeriodManager.sol (line 58)
        uint256[] memory _totalCaps,
  1. File: contracts/hyphen/interfaces/IWhiteListPeriodManager.sol (line 59)
        uint256[] memory _perTokenWalletCaps
  1. File: contracts/hyphen/interfaces/IWhiteListPeriodManager.sol (line 62)
    function setIsExcludedAddressStatus(address[] memory _addresses, bool[] memory _status) external;
  1. File: contracts/hyphen/interfaces/IWhiteListPeriodManager.sol (line 62)
    function setIsExcludedAddressStatus(address[] memory _addresses, bool[] memory _status) external;
  1. File: contracts/hyphen/interfaces/ISvgHelper.sol (line 29)
    function setBackgroundPngUrl(string memory _backgroundPngUrl) external;
  1. File: contracts/hyphen/interfaces/ILPToken.sol (line 18)
        string memory _name,
  1. File: contracts/hyphen/interfaces/ILPToken.sol (line 19)
        string memory _symbol,
  1. File: contracts/hyphen/interfaces/ILPToken.sol (line 51)
        bytes memory _data
  1. File: contracts/hyphen/interfaces/ILPToken.sol (line 89)
    function updateTokenMetadata(uint256 _tokenId, LpTokenMetadata memory _lpTokenMetadata) external;
  1. File: contracts/hyphen/LiquidityPool.sol (line 199)
        string memory tag
  1. File: contracts/hyphen/LiquidityPool.sol (line 223)
        string memory tag
  1. File: contracts/hyphen/LiquidityPool.sol (line 245)
        string memory tag
  1. File: contracts/hyphen/LiquidityPool.sol (line 267)
        bytes memory depositHash,
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 178)
    function setIsExcludedAddressStatus(address[] memory _addresses, bool[] memory _status) external onlyOwner {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 178)
    function setIsExcludedAddressStatus(address[] memory _addresses, bool[] memory _status) external onlyOwner {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 220)
        address[] memory _tokens,
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 221)
        uint256[] memory _totalCaps,
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 222)
        uint256[] memory _perTokenWalletCaps

internal functions only called once should be inlined to save gas

  1. File: contracts/hyphen/token/svg-helpers/SvgHelperBase.sol (line 40)
    function _getZeroString(uint256 _length) internal pure returns (string memory) {
  1. File: contracts/hyphen/token/svg-helpers/SvgHelperBase.sol (line 52)
    function _truncateDigitsFromRight(uint256 _number, uint256 _digitsCount) internal pure returns (uint256) {
  1. File: contracts/hyphen/token/svg-helpers/SvgHelperBase.sol (line 143)
    function _calculatePercentage(uint256 _num, uint256 _denom) internal pure returns (string memory) {
  1. File: contracts/hyphen/LiquidityPool.sol (lines 308-313)
    function getAmountToTransfer(
        uint256 initialGas,
        address tokenAddress,
        uint256 amount,
        uint256 tokenGasPrice
    ) internal returns (uint256 amountToTransfer) {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 76)
    function _isSupportedToken(address _token) internal view returns (bool) {
  1. File: contracts/security/Pausable.sol (line 59)
    function _changePauser(address newPauser) internal {

Not using the named return variables when a function returns, wastes deployment gas

  1. File: contracts/hyphen/token/TokenManager.sol (line 140)
        return ERC2771Context._msgSender();
  1. File: contracts/hyphen/LiquidityFarming.sol (line 353)
        return ERC2771ContextUpgradeable._msgSender();
  1. File: contracts/hyphen/LiquidityPool.sol (line 418)
        return ERC2771ContextUpgradeable._msgSender();
  1. File: contracts/hyphen/LiquidityProviders.sol (line 459)
        return ERC2771ContextUpgradeable._msgSender();
  1. File: contracts/hyphen/metatx/ERC2771Context.sol (line 28)
            return super._msgSender();
  1. File: contracts/hyphen/metatx/ERC2771ContextUpgradeable.sol (line 36)
            return super._msgSender();

Using private rather than public for constants, saves gas

If needed, the value can be read from the verified contract source code

  1. File: contracts/hyphen/LiquidityProviders.sol (line 27)
    uint256 public constant BASE_DIVISOR = 10**18;

Splitting require() statements that use && saves gas

See this issue for an example

  1. File: contracts/hyphen/token/TokenManager.sol (lines 74-77)
        require(
            (toChainId.length == tokenAddresses.length) && (tokenAddresses.length == tokenConfig.length),
            " ERR_ARRAY_LENGTH_MISMATCH"
        );
  1. File: contracts/hyphen/LiquidityPool.sol (lines 156-160)
        require(
            tokenManager.getDepositConfig(toChainId, tokenAddress).min <= amount &&
                tokenManager.getDepositConfig(toChainId, tokenAddress).max >= amount,
            "Deposit amount not in Cap limit"
        );
  1. File: contracts/hyphen/LiquidityPool.sol (lines 247-251)
        require(
            tokenManager.getDepositConfig(toChainId, NATIVE).min <= msg.value &&
                tokenManager.getDepositConfig(toChainId, NATIVE).max >= msg.value,
            "Deposit amount not in Cap limit"
        );
  1. File: contracts/hyphen/LiquidityPool.sol (lines 272-276)
        require(
            tokenManager.getTransferConfig(tokenAddress).min <= amount &&
                tokenManager.getTransferConfig(tokenAddress).max >= amount,
            "Withdraw amnt not in Cap limits"
        );
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (lines 224-227)
        require(
            _tokens.length == _totalCaps.length && _totalCaps.length == _perTokenWalletCaps.length,
            "ERR__LENGTH_MISMACH"
        );

Using > 0 costs more gas than != 0 when used on a uint in a require() statement

  1. File: contracts/hyphen/LiquidityProviders.sol (line 239)
        require(_amount > 0, "ERR__AMOUNT_IS_0");
  1. File: contracts/hyphen/LiquidityProviders.sol (line 283)
        require(_amount > 0, "ERR__AMOUNT_IS_0");
  1. File: contracts/hyphen/LiquidityProviders.sol (line 410)
        require(lpFeeAccumulated > 0, "ERR__NO_REWARDS_TO_CLAIM");

require()/revert() strings longer than 32 bytes cost extra gas

  1. File: contracts/hyphen/token/LPToken.sol (line 70)
        require(_whiteListPeriodManager != address(0), "ERR_INVALID_WHITELIST_PERIOD_MANAGER");
  1. File: contracts/hyphen/ExecutorManager.sol (line 17)
        require(executorStatus[msg.sender], "You are not allowed to perform this operation");
  1. File: contracts/hyphen/LiquidityPool.sol (line 77)
        require(_msgSender() == address(liquidityProviders), "Only liquidityProviders is allowed");
  1. File: contracts/security/Pausable.sol (line 43)
        require(isPauser(msg.sender), "Only pauser is allowed to perform this operation");

State variables should be cached in stack variables rather than re-reading them from storage

The instances below point to the second access of a state variable within a function

  1. File: contracts/hyphen/token/LPToken.sol (line 132)
            ILiquidityProviders(liquidityProvidersAddress).totalReserve(tokenAddress)
  1. File: contracts/hyphen/token/LPToken.sol (line 126)
            tokenMetadata[tokenId].suppliedLiquidity,
  1. File: contracts/hyphen/token/LPToken.sol (line 193)
                tokenMetadata[tokenId].suppliedLiquidity
  1. File: contracts/hyphen/token/LPToken.sol (line 122)
        ISvgHelper svgHelper = ISvgHelper(svgHelpers[tokenAddress]);
  1. File: contracts/hyphen/token/TokenManager.sol (line 52)
        tokensInfo[tokenAddress].maxFee = _maxFee;
  1. File: contracts/hyphen/token/TokenManager.sol (line 96)
        tokensInfo[tokenAddress].tokenConfig = transferConfig[tokenAddress];
  1. File: contracts/hyphen/token/TokenManager.sol (line 118)
            tokensInfo[tokenAddress].supportedToken,
  1. File: contracts/hyphen/token/TokenManager.sol (line 80)
            depositConfig[toChainId[index]][tokenAddresses[index]].max = tokenConfig[index].max;
  1. File: contracts/hyphen/token/TokenManager.sol (line 95)
        transferConfig[tokenAddress].max = maxCapLimit;
  1. File: contracts/hyphen/token/TokenManager.sol (line 112)
        transferConfig[tokenAddress].max = maxCapLimit;
  1. File: contracts/hyphen/LiquidityFarming.sol (line 200)
            lpToken.isApprovedForAll(msgSender, address(this)) || lpToken.getApproved(_nftId) == address(this),
  1. File: contracts/hyphen/LiquidityFarming.sol (line 250)
        lpToken.safeTransferFrom(address(this), msgSender, _nftId);
  1. File: contracts/hyphen/LiquidityFarming.sol (line 290)
        return accumulator + poolInfo[_baseToken].accTokenPerShare;
  1. File: contracts/hyphen/LiquidityFarming.sol (line 150)
                IERC20Upgradeable rewardToken = IERC20Upgradeable(rewardTokens[baseToken]);
  1. File: contracts/hyphen/LiquidityFarming.sol (line 234)
            if (nftIdsStaked[msgSender][index] == _nftId) {
  1. File: contracts/hyphen/LiquidityFarming.sol (line 323)
            emit LogUpdatePool(_baseToken, pool.lastRewardTime, totalSharesStaked[_baseToken], pool.accTokenPerShare);
  1. File: contracts/hyphen/LiquidityFarming.sol (line 276)
                    rewardRateLog[_baseToken][i].rewardsPerSecond *
  1. File: contracts/hyphen/LiquidityFarming.sol (line 334)
        return rewardRateLog[_baseToken][rewardRateLog[_baseToken].length - 1].rewardsPerSecond;
  1. File: contracts/hyphen/LiquidityPool.sol (line 158)
                tokenManager.getDepositConfig(toChainId, tokenAddress).max >= amount,
  1. File: contracts/hyphen/LiquidityPool.sol (line 249)
                tokenManager.getDepositConfig(toChainId, NATIVE).max >= msg.value,
  1. File: contracts/hyphen/LiquidityPool.sol (line 274)
                tokenManager.getTransferConfig(tokenAddress).max >= amount,
  1. File: contracts/hyphen/LiquidityPool.sol (line 318)
            lpFee = (amount * tokenManager.getTokensInfo(tokenAddress).equilibriumFee) / BASE_DIVISOR;
  1. File: contracts/hyphen/LiquidityPool.sol (line 349)
        uint256 maxFee = tokenManager.getTokensInfo(tokenAddress).maxFee;
  1. File: contracts/hyphen/LiquidityPool.sol (line 137)
            liquidityProviders.totalLPFees(tokenAddress) -
  1. File: contracts/hyphen/LiquidityPool.sol (line 335)
        gasFeeAccumulatedByToken[tokenAddress] = gasFeeAccumulatedByToken[tokenAddress] + gasFee;
  1. File: contracts/hyphen/LiquidityPool.sol (line 377)
        gasFeeAccumulatedByToken[tokenAddress] = gasFeeAccumulatedByToken[tokenAddress] - _gasFeeAccumulated;
  1. File: contracts/hyphen/LiquidityPool.sol (line 386)
        gasFeeAccumulatedByToken[NATIVE] = gasFeeAccumulatedByToken[NATIVE] - _gasFeeAccumulated;
  1. File: contracts/hyphen/LiquidityPool.sol (line 336)
        gasFeeAccumulated[tokenAddress][_msgSender()] = gasFeeAccumulated[tokenAddress][_msgSender()] + gasFee;
  1. File: contracts/hyphen/LiquidityPool.sol (line 378)
        gasFeeAccumulated[tokenAddress][_msgSender()] = 0;
  1. File: contracts/hyphen/LiquidityPool.sol (line 387)
        gasFeeAccumulated[NATIVE][_msgSender()] = 0;
  1. File: contracts/hyphen/LiquidityPool.sol (line 167)
            incentivePool[tokenAddress] = incentivePool[tokenAddress] - rewardAmount;
  1. File: contracts/hyphen/LiquidityPool.sol (line 184)
                rewardAmount = (amount * incentivePool[tokenAddress] * 10000000000) / liquidityDifference;
  1. File: contracts/hyphen/LiquidityPool.sol (line 257)
            incentivePool[NATIVE] = incentivePool[NATIVE] - rewardAmount;
  1. File: contracts/hyphen/LiquidityPool.sol (line 320)
                (incentivePool[tokenAddress] +
  1. File: contracts/hyphen/LiquidityProviders.sol (line 204)
        (address _tokenAddress, uint256 nftSuppliedLiquidity, uint256 totalNFTShares) = lpToken.tokenMetadata(_nftId);
  1. File: contracts/hyphen/LiquidityProviders.sol (line 242)
        lpToken.updateTokenMetadata(nftId, data);
  1. File: contracts/hyphen/LiquidityProviders.sol (line 305)
        lpToken.updateTokenMetadata(_nftId, data);
  1. File: contracts/hyphen/LiquidityProviders.sol (line 436)
        lpToken.updateTokenMetadata(_nftId, LpTokenMetadata(_tokenAddress, nftSuppliedLiquidity, nftShares));
  1. File: contracts/hyphen/LiquidityProviders.sol (line 291)
            mintedSharesAmount = (_amount * totalSharesMinted[token]) / totalReserve[token];
  1. File: contracts/hyphen/LiquidityProviders.sol (line 137)
        emit CurrentLiquidityChanged(tokenAddress, currentLiquidity[tokenAddress]-amount, currentLiquidity[tokenAddress]);
  1. File: contracts/hyphen/LiquidityProviders.sol (line 142)
        emit CurrentLiquidityChanged(tokenAddress, currentLiquidity[tokenAddress]+amount, currentLiquidity[tokenAddress]);
  1. File: contracts/hyphen/LiquidityProviders.sol (line 183)
            return totalSharesMinted[_baseToken] / totalReserve[_baseToken];
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 249)
            uint256 liquidity = totalLiquidityByLp[_token][lpToken.ownerOf(i)];
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 261)
        return !areWhiteListRestrictionsEnabled || (areWhiteListRestrictionsEnabled && _cond);
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 98)
        totalLiquidityByLp[_token][_lp] += _amount;

Using bools for storage incurs overhead

// Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled.

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/58f635312aa21f947cae5f8578638a85aa2519f5/contracts/security/ReentrancyGuard.sol#L23-L27

  1. File: contracts/hyphen/ExecutorManager.sol (line 10)
    mapping(address => bool) internal executorStatus;
  1. File: contracts/hyphen/LiquidityPool.sol (line 37)
    mapping(bytes32 => bool) public processedHash;
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 19)
    bool public areWhiteListRestrictionsEnabled;
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 23)
    mapping(address => bool) public isExcludedAddress;

Functions guaranteed to revert when called by normal users can be marked payable

If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided.

  1. File: contracts/hyphen/token/LPToken.sol (line 56)
    function setSvgHelper(address _tokenAddress, ISvgHelper _svgHelper) public onlyOwner {
  1. File: contracts/hyphen/token/LPToken.sol (line 63)
    function setLiquidityProviders(address _liquidityProviders) external onlyOwner {
  1. File: contracts/hyphen/token/LPToken.sol (line 69)
    function setWhiteListPeriodManager(address _whiteListPeriodManager) external onlyOwner {
  1. File: contracts/hyphen/token/LPToken.sol (line 83)
    function mint(address _to) external onlyHyphenPools whenNotPaused nonReentrant returns (uint256) {
  1. File: contracts/hyphen/token/LPToken.sol (lines 89-92)
    function updateTokenMetadata(uint256 _tokenId, LpTokenMetadata memory _lpTokenMetadata)
        external
        onlyHyphenPools
        whenNotPaused
  1. File: contracts/hyphen/token/svg-helpers/SvgHelperBase.sol (line 20)
    function setTokenDecimals(uint256 _tokenDecimals) public onlyOwner {
  1. File: contracts/hyphen/token/TokenManager.sol (lines 44-48)
    function changeFee(
        address tokenAddress,
        uint256 _equilibriumFee,
        uint256 _maxFee
    ) external override onlyOwner whenNotPaused {
  1. File: contracts/hyphen/token/TokenManager.sol (lines 56-59)
    function setTokenTransferOverhead(address tokenAddress, uint256 gasOverhead)
        external
        tokenChecks(tokenAddress)
        onlyOwner
  1. File: contracts/hyphen/token/TokenManager.sol (lines 69-73)
    function setDepositConfig(
        uint256[] memory toChainId,
        address[] memory tokenAddresses,
        TokenConfig[] memory tokenConfig
    ) external onlyOwner {
  1. File: contracts/hyphen/token/TokenManager.sol (lines 84-90)
    function addSupportedToken(
        address tokenAddress,
        uint256 minCapLimit,
        uint256 maxCapLimit,
        uint256 equilibriumFee,
        uint256 maxFee
    ) external onlyOwner {
  1. File: contracts/hyphen/token/TokenManager.sol (line 101)
    function removeSupportedToken(address tokenAddress) external tokenChecks(tokenAddress) onlyOwner {
  1. File: contracts/hyphen/token/TokenManager.sol (lines 105-109)
    function updateTokenCap(
        address tokenAddress,
        uint256 minCapLimit,
        uint256 maxCapLimit
    ) external tokenChecks(tokenAddress) onlyOwner {
  1. File: contracts/hyphen/ExecutorManager.sol (line 30)
    function addExecutors(address[] calldata executorArray) external override onlyOwner {
  1. File: contracts/hyphen/ExecutorManager.sol (line 37)
    function addExecutor(address executorAddress) public override onlyOwner {
  1. File: contracts/hyphen/ExecutorManager.sol (line 46)
    function removeExecutors(address[] calldata executorArray) external override onlyOwner {
  1. File: contracts/hyphen/ExecutorManager.sol (line 53)
    function removeExecutor(address executorAddress) public override onlyOwner {
  1. File: contracts/hyphen/LiquidityFarming.sol (lines 96-100)
    function initalizeRewardPool(
        address _baseToken,
        address _rewardToken,
        uint256 _rewardPerSecond
    ) external onlyOwner {
  1. File: contracts/hyphen/LiquidityFarming.sol (line 169)
    function setRewardPerSecond(address _baseToken, uint256 _rewardPerSecond) public onlyOwner {
  1. File: contracts/hyphen/LiquidityFarming.sol (lines 180-184)
    function reclaimTokens(
        address _token,
        uint256 _amount,
        address payable _to
    ) external nonReentrant onlyOwner {
  1. File: contracts/hyphen/LiquidityPool.sol (line 107)
    function setTrustedForwarder(address trustedForwarder) public onlyOwner {
  1. File: contracts/hyphen/LiquidityPool.sol (line 113)
    function setLiquidityProviders(address _liquidityProviders) public onlyOwner {
  1. File: contracts/hyphen/LiquidityPool.sol (line 119)
    function setBaseGas(uint128 gas) external onlyOwner {
  1. File: contracts/hyphen/LiquidityPool.sol (line 127)
    function setExecutorManager(address _executorManagerAddress) external onlyOwner {
  1. File: contracts/hyphen/LiquidityPool.sol (lines 263-270)
    function sendFundsToUser(
        address tokenAddress,
        uint256 amount,
        address payable receiver,
        bytes memory depositHash,
        uint256 tokenGasPrice,
        uint256 fromChainId
    ) external nonReentrant onlyExecutor tokenChecks(tokenAddress) whenNotPaused {
  1. File: contracts/hyphen/LiquidityPool.sol (line 372)
    function withdrawErc20GasFee(address tokenAddress) external onlyExecutor whenNotPaused nonReentrant {
  1. File: contracts/hyphen/LiquidityPool.sol (line 383)
    function withdrawNativeGasFee() external onlyExecutor whenNotPaused nonReentrant {
  1. File: contracts/hyphen/LiquidityPool.sol (lines 394-398)
    function transfer(
        address _tokenAddress,
        address receiver,
        uint256 _tokenAmount
    ) external whenNotPaused onlyLiquidityProviders nonReentrant {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 116)
    function setLpToken(address _lpToken) external onlyOwner {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 127)
    function increaseCurrentLiquidity(address tokenAddress, uint256 amount) public onlyLiquidityPool {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 131)
    function decreaseCurrentLiquidity(address tokenAddress, uint256 amount) public onlyLiquidityPool {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 148)
    function setTokenManager(address _tokenManager) external onlyOwner {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 163)
    function setWhiteListPeriodManager(address _whiteListPeriodManager) external onlyOwner {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 171)
    function setLiquidityPool(address _liquidityPool) external onlyOwner {
  1. File: contracts/hyphen/LiquidityProviders.sol (line 229)
    function addLPFee(address _token, uint256 _amount) external onlyLiquidityPool tokenChecks(_token) whenNotPaused {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (lines 104-108)
    function beforeLiquidityAddition(
        address _lp,
        address _token,
        uint256 _amount
    ) external onlyLiquidityPool whenNotPaused {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (lines 130-134)
    function beforeLiquidityRemoval(
        address _lp,
        address _token,
        uint256 _amount
    ) external onlyLiquidityPool whenNotPaused {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (lines 141-146)
    function beforeLiquidityTransfer(
        address _from,
        address _to,
        address _token,
        uint256 _amount
    ) external onlyLpNft whenNotPaused {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 158)
    function setTokenManager(address _tokenManager) external onlyOwner {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 166)
    function setLiquidityProviders(address _liquidityProviders) external onlyOwner {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 174)
    function setLpToken(address _lpToken) external onlyOwner {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 178)
    function setIsExcludedAddressStatus(address[] memory _addresses, bool[] memory _status) external onlyOwner {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 186)
    function setTotalCap(address _token, uint256 _totalCap) public tokenChecks(_token) onlyOwner {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 202)
    function setPerTokenWalletCap(address _token, uint256 _perTokenWalletCap) public tokenChecks(_token) onlyOwner {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (lines 210-214)
    function setCap(
        address _token,
        uint256 _totalCap,
        uint256 _perTokenWalletCap
    ) public onlyOwner {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (lines 219-223)
    function setCaps(
        address[] memory _tokens,
        uint256[] memory _totalCaps,
        uint256[] memory _perTokenWalletCaps
    ) external onlyOwner {
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 237)
    function setAreWhiteListRestrictionsEnabled(bool _status) external onlyOwner {
  1. File: contracts/security/Pausable.sol (line 51)
    function changePauser(address newPauser) public onlyPauser {
  1. File: contracts/security/Pausable.sol (line 65)
    function renouncePauser() external virtual onlyPauser {
  1. File: contracts/security/Pausable.sol (line 70)
    function pause() public onlyPauser {
  1. File: contracts/security/Pausable.sol (line 74)
    function unpause() public onlyPauser {

Use a solidity version of at least 0.8.2 to get compiler automatic inlining

Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads

Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require() strings

  1. File: contracts/interfaces/IERC20Permit.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/LPToken.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/Polygon/Polygon.USDT.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/Polygon/Polygon.ETH.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/Polygon/Polygon.BICO.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/Polygon/Polygon.USDC.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/Avalanche/Avalanche.ETH.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/Avalanche/Avalanche.BICO.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/Avalanche/Avalanche.USDT.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/Avalanche/Avalanche.USDC.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/Ethereum/Ethereum.USDC.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/Ethereum/Ethereum.BICO.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/Ethereum/Ethereum.ETH.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/Ethereum/Ethereum.USDT.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/svg-helpers/SvgHelperBase.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/token/TokenManager.sol (line 3)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/ExecutorManager.sol (line 3)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/LiquidityFarming.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/interfaces/ILiquidityPool.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/interfaces/IExecutorManager.sol (line 3)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/interfaces/ILiquidityProviders.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/interfaces/IWhiteListPeriodManager.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/interfaces/ISvgHelper.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/interfaces/ILPToken.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/interfaces/ITokenManager.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/LiquidityPool.sol (line 3)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/structures/LpTokenMetadata.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/LiquidityProviders.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/WhitelistPeriodManager.sol (line 2)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/metatx/ERC2771Context.sol (line 3)
pragma solidity 0.8.0;
  1. File: contracts/hyphen/metatx/ERC2771ContextUpgradeable.sol (line 3)
pragma solidity 0.8.0;
  1. File: contracts/security/Pausable.sol (line 3)
pragma solidity 0.8.0;
AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter