BeamSwap - Smart Contract Audit Report

Audit Summary

BeamSwap Audit Report BeamSwap is building a new decentralized automated liquidity protocol trading platform that is used to exchange cryptocurrencies, with additional contracts offering the ability to stake for rewards.

For this audit, we reviewed the contracts folder at commit 54319c0a9f907d5960fcb3c689d362de21f1751c on the team's GitHub repository.

Audit Findings

Please ensure trust in the team prior to investing as they have substantial control in the ecosystem. The team intends to transfer ownership to the TimeLock contract described below.

Date: January 5th, 2022.
Updated: January 6th, 2022 with updated logic and additional checks when users send funds.

BeamSplitter.sol - Finding #1 - Low

Description: The swapping done within the contract is open to potential frontrunning.
			
(uint256 reserve0, uint256 reserve1, ) = pair.getReserves();
uint256 amountInWithFee = amountIn.mul(997);
if (fromToken == pair.token0()) {
	amountOut =
		amountInWithFee.mul(reserve1) /
		reserve0.mul(1000).add(amountInWithFee);
	IERC20(fromToken).safeTransfer(address(pair), amountIn);
	pair.swap(0, amountOut, to, new bytes(0));
} else {
	amountOut =
		amountInWithFee.mul(reserve0) /
		reserve1.mul(1000).add(amountInWithFee);
	IERC20(fromToken).safeTransfer(address(pair), amountIn);
	pair.swap(amountOut, 0, to, new bytes(0));
}

Risk/Impact: A frontrunner could manipulate the reserves of the liquidity pool resulting in an arbitrage opportunity.
Recommendation: Implementing a Time Weighted Average Price (TWAP) to mitigate the potential price manipulations that allow frontrunning.

Contracts Overview

BeamSwapERC20 Contract:
  • The BeamSwapERC20 contract implements the ERC20 standard for use as an LP token.
  • This contract utilizes a "permit" mechanism which allows the owner of the $BEAM-LP tokens to sign a transaction that enables another user to withdraw tokens and send them to the recipient. The recipient then submits the permit on behalf of the owner.
BeamSwapFactory Contract:
  • The BeamSwapFactory contract is responsible for the creation of liquidity pairs for two tokens, thereby enabling trading on the platform.
  • When creating a new trading pair, the BeamSwapPair initialize() function is called which allows the factory to specify the two ERC20 tokens that this pair will exchange.
  • Once the pool is created, its address is stored with a double mapping that takes both token addresses as input.
BeamSwapPair Contract:
  • The BeamSwapPair contract is the core BeamSwap trading functionality.
  • Each BeamSwapPair manages a liquidity pool made up of reserves of two ERC-20 tokens.
  • This contract is responsible for tracking the balance of both tokens in the pair, as well as mints and burns of the LP token.
  • Users can add liquidity by providing an equivalent value of each token and are minted an LP token in return. The LP tokens may be burned to receive the underlying assets at any time.
  • Users may also exchange one token for an equivalent amount of the other token based on the current market value.
  • A 0.3% fee is taken on an exchange between tokens and given as rewards to LP providers.
  • Of the 0.3% fee collected, 0.13% is taken on liquidity adds and burns. The team will distribute this as follows: 0.03% for beamshare, 0.05% for token burn, 0.05% for treasury.
BeamSwapRouter Contract:
  • The BeamSwapRouter contract is used to interact with liquidity pools that are created via the BeamSwapFactory contract.
  • BeamSwapRouter routes orders to the user-determined pair contract to swap assets.
  • This contract performs requirement checks needed for swapping tokens, adding liquidity, and removing liquidity.
BeamSwapToken Contract:
  • GLINT tokens are earned as rewards for interacting with the BeamSwap platform.
  • The max total supply of GLINT is 3,000,000,000.
  • Each GLINT token additionally represents votes intended to be used in a DAO where one token represents one vote.
  • Users may delegate their votes to another address allowing them to vote on behalf of the user.
  • Once votes are delegated, the user must explicitly delegate back to themselves to regain their votes.
  • Users also have the option to delegate through the use of a signed message, allowing for a gasless delegation for the user.
BeamShare Contract:
  • Users may deposit GLINT tokens and will receive back SHARES tokens dependent on the ratio of total SHARES tokens and the current supply of GLINT tokens in the contract.
  • Users may withdraw their GLINT at any time and will receive back a proportional number of GLINT tokens.
  • Each SHARES token additionally represents votes intended to be used in a DAO where one token represents one vote.
  • Users may delegate their votes to another address allowing them to vote on behalf of the user.
  • Once votes are delegated, the user must explicitly delegate back to themselves to regain their votes.
  • Users also have the option to delegate through the use of a signed message, allowing for a gasless delegation for the user.
BeamChef Contract:
  • Any user may deposit specified tokens into staking pools to earn rewards in GLINT tokens and potentially other rewards from additional reward distributors.
  • Users may additionally provide a signed message to the contract allowing them to approve and deposit in one transaction to save on gas fees.
  • Users will receive a reward amount on each block based on the amount staked and the amount of points allocated to the pool.
  • Users may only claim their rewards once per "harvest" period. Each pool has its own harvest period and may vary between pools, with a maximum allowed harvest period of 14 days.
  • On deposits and withdrawals, pending rewards are calculated and minted to the user, if eligible.
  • Users may additionally provide a list of pool ids to harvest any available rewards from each specified pool.
  • There is a deposit fee of up to 10% which is transferred to a Fee address controlled by the team. Each pool has its own deposit fee and may vary between pools.
  • Additionally, a Beam Fee is taken from distributed GLINT rewards and transferred to a Beam Share wallet controlled by the team.
  • The user can also trigger an emergency withdraw, which will transfer all the user's deposited LP tokens to their wallet address, without calculating rewards.
  • The owner may update the rewards emission rate and points allocated to each pool to any value at any time.
  • The owner may update the deposit fee, harvest interval, and additional reward distributors for each pool at any time.
  • The Beam Share and Fee addresses may update their own address at any time.
  • The owner may update the Beam Share fee to any value at any time.
MultipleRewards Contract:
  • This contract is used in conjunction with the BeamChef contract to reward stakers in additional types of tokens.
  • Users will receive a reward amount on each block based on the amount staked in the corresponding BeamChef pool, the reward emission rate, and the amount of points allocated to the pool.
  • Rewards are claimed when users deposit, withdraw, or emergency withdraw in the BeamChef contract.
  • Sufficient rewards tokens must be supplied to the contract, otherwise rewards will fail to be distributed once the supply is exhausted.
  • Once a pool is added, the reward info that determines the reward period and emission rate must be added separately for each pool.
  • The team should exercise caution when adding fee on transfer tokens as rewards, and if doing so must ensure a proper exclusion from fees.
  • The owner may add a pool and its corresponding reward info at any time.
  • The owner may add additional reward info, extending the rewards period at any time.
  • The owner may "emergency withdraw" any rewards tokens that have not already been distributed at any time.
TimeLock Contract:
  • This contract is used to execute arbitrary logic approved by an admin, after a specified time period has elapsed.
  • The admin, which is initially declared upon deployment, may submit transactions and a specified unlock time where they are subsequently added to a queue.
  • Once the unlock time has passed and the current time is still within the grace period of 2 weeks, the admin may execute the transaction.
  • The admin may also elect to cancel a transaction at any time, making it unable to be executed.
  • The admin may set a pending admin once after deployment. After this first pending admin is set, any future pending admins must be set through a transaction from the queue.
  • Once the pending admin has been set, they may claim the admin role at anytime.
  • After deployment, the minimum and maximum delays allowed can only be updated through the use of a transaction from the queue.
Vesting Contract:
  • Users are able to claim designated vesting tokens distributed over periods of a specified number of days from the start date.
  • Users are able to claim rewards once per period.
  • The contract must be provided a sufficient number of tokens, otherwise some users will not be able to claim all the tokens they are entitled.
  • The owner may add vesting recipients and adjust the amount of tokens received per period until the start date is set.
  • The owner is able to withdraw any non-vesting ERC20 token in the contract at any time.
  • The owner may set the start date only once after deployment.
BeamLocker Contract:
  • Any user may deposit any ERC20 token for a fee paid in GLMR. As any token can be deposited into the locker, it is possible for a malicious token to manipulate its balance within the contract. This will not have any effect on any other locked tokens.
  • Users specify a withdrawer and a withdraw time when depositing; after the withdraw time has passed, the withdrawer may then claim the deposited tokens from the contract.
  • The deposit fee is sent to a Marketing wallet controlled by the team.
  • The owner may update the Marketing address at any time.
  • The owner may update the lock fee to any value at any time.
BeamSplitter Contract:
  • Any user may transfer LP tokens to this contract in order to convert them to GLINT, which is subsequently sent to a Burn address.
  • Once LP tokens have been sent to the contract, any externally owned address (EOA) may trigger the burning of the LP tokens.
  • The contract will then burn the LP tokens for the underlying assets, swapping any non-GLINT token for GLINT using a bridge.
  • All GLINT is then sent to a Burner address, which is set upon deployment.
  • Users also have the option to burn multiple different specified LP tokens at once.
  • The owner may set and update the bridge for any token at any time.
FeeLessTransfer Contract:
  • Any user is able to use this contract to swap any token on the whitelist for GLMR.
  • Swapping supports a gasless approval for the user through the use of an off chain signed message. The execution of the swap itself will still incur the cost of execution.
  • A percentage fee is taken from any received GLMR and transferred to a Fee wallet controller by the team, if one has been set.
  • The owner may add and remove any token from the whitelist at any time.
  • The owner may set the fee percentage to any value less than 100% at any time.
  • The owner may update the address of the BeamSwapRouter used to swap at any time.
  • The owner may withdraw any token and GLMR in the contract at any time.

Resolved Issues

Vesting.sol - Resolved Issue #1 - High

Description: When updating the amount of tokens a user receives per vesting period, the total amount of tokens vested per period is incorrectly adjusted.
Risk/Impact: The total tokens vested per period being inaccurate can lead to the total amount of tokens provided to the contract for vesting to be insufficient, subsequently preventing users from receiving tokens they are entitled.
Recommendation: The totalShares variable should be calculated using both the oldUserShare and the _dailyShare variables. One way to do so would be as such: totalShares = totalShares + _dailyShare - oldUserShare
Resolution: The team has implemented the solution described above.

BeamLocker.sol - Resolved Issue #1 - Low

Description: Any extra of the blockchain's native token provided to pay the "lock fee" is not returned to the user.
Risk/Impact: Users may inadvertently send more of the native token than required and subsequently lose all of the extra token sent.
Recommendation: Require that the amount of native token sent is equal to the lock fee.
Resolution: The message value is now required to be the correct amount. This prevents any extra funds from being sent to pay the lock fee.

External Threat Results

Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Centralization of Control
  • The team retains ownership controls outlined above,
    with the intent to transfer ownership to the TimeLock contract.
  • There are several instances of uncapped fees.
  • The owner may withdraw any non-distributed tokens from the MultipleRewards contract.
  • Signed messages require the use of off chain logic.
  • WARNING
    Delegate Call to Untrusted ContractN/APASS
    Dependence on Predictable VariablesN/APASS
    Deprecated OpcodesN/APASS
    Ether ThiefN/APASS
    ExceptionsN/APASS
    External CallsN/APASS
    Integer Over/UnderflowN/APASS
    Logical IssuesN/APASS
    Multiple SendsN/APASS
    SuicideN/APASS
    State Change External CallsN/APass
    Unchecked RetvalN/APASS
    User Supplied AssertionN/APASS
    Critical Solidity CompilerN/APASS
    Overall Contract Safety PASS

    Contract Source Summary and Visualizations

    Name

    Address/Source Code

    Visualized
    (Hover-Zoom Recommended)

    BeamChef

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.

    BeamLocker

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.

    BeamShare

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.

    BeamSplitter

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.

    BeamSwapERC20

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.

    BeamSwapFactory

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.

    BeamSwapPair

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.

    BeamSwapRouter

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.

    BeamSwapToken

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.

    FeeLessSwap

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.

    MultipleRewards

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.

    TimeLock

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.

    Vesting

    GitHub (Not yet deployed on mainnet)

    Function Graph.  Inheritance Chart.