Skip to content
$1,000,000 in security audit grants are live now, Apply here →

Security review · March 2024

MIMSwap

for Abracadabra Money

MIMSwap engaged Guardian to review the security of its PMM exchange. From the 29th of February to the 11th of March, a team of 6 auditors reviewed the source code in scope.

Published
Review window
February 29 to March 11, 2024
Language
Solidity
Chains
Blast
Sector
Lending
  • 1 Critical
  • 5 High
  • 7 Medium
  • 15 Low
  • 0 Informational

22 resolved · 1 partially resolved · 5 acknowledged

Scope

Overview

MIMSwap engaged Guardian to review the security of its PMM exchange. From the 29th of February to the 11th of March, a team of 6 auditors reviewed the source code in scope.

Findings 28

  1. C-01 Critical Claiming Yield DoS DoS Resolved
    Location
    Global

    Description

    The BlastMagicLP and BlastOnboarding contracts do not expect to hold native Ether and therefore will not accrue claimable native ether yield, however they still attempt to claim native yield with the BlastYields.claimAllNativeYields function.

    The implementation of the BLAST_YIELD contract in go reverts if there is not any claimable Ether:

    https://github.com/blast-io/blast/blob/c39cdf1fa7ef9e0d4eaf64a7a5cf7b3c46c739fd/blast-geth/c

    ore/vm/contracts.go#L1239

    Recommendation

    Either do not invoke the claimAllNativeYields function if there is no native yield to be claimed, or separate the yield claiming logic into independent functions for each type of yield.

    Resolution

    Abracadabra Team: Resolved.

  2. H-01 High Weth Transferred From The Wrong Address Logical Error Resolved
    Location
    Router.sol: 78

    Description

    In the Router.createPoolETH function, a deposit to the weth contract is made but then a subsequent weth safeTransferFrom is made from the msg.sender to the newly created pool.

    As a result, users may accidentally pay twice for the WETH the pool should be created with if they had approved the Router contract. The native Ether sent to the Router will be lost.

    Recommendation

    Use the weth safeTransferFrom to transfer from the Router contract to the newly created pool rather than from the msg.sender.

    Resolution

    Abracadabra Team: Resolved.

  3. H-02 High twapUpdate Overflow DoS DoS Resolved
    Location
    MagicLP.sol

    Description

    In MagicLP.sol, _twapUpdate is called every time setReserve or sync is called. The update adds to _BASE_PRICE_CUMULATIVE_LAST_ which is an ever increasing value. In DODO v2, because they use an older version of solidity, it is desired and expected for this value to overflow once it has hit the max of type.uint256.

    However for MagicLP which uses a newer solidity version, this cannot overflow and all contract functionality will be bricked.

    Recommendation

    Wrap with an unchecked block to allow for overflow.

    Resolution

    Abracadabra Team: Resolved.

  4. H-03 High previewAddLiquidity Incorrect quoteBalance Logical Error Resolved
    Location
    Router.sol: 90

    Description

    In the previewAddLiquidity function the quoteBalance is intended to account for the current balance of the quote tokens in the LP as well as the new quote tokens which will be added to the LP. However the quoteBalance is the balance of quote tokens + the baseInAmount: uint256 quoteBalance = IMagicLP(lp)._QUOTE_TOKEN_().balanceOf(address(lp)) + baseInAmount;

    Recommendation

    Correct the quoteBalance to be: uint256 quoteBalance = IMagicLP(lp)._QUOTE_TOKEN_().balanceOf(address(lp)) + quoteInAmount;

    Resolution

    Abracadabra Team: Resolved.

  5. H-04 High Lacking Gas Yields Claiming Logic Logical Error Partially resolved
    Location
    Global

    Description

    There are several contracts in the Abracadabra and Mimswap systems that cannot claim gas yields as they accrue. These contracts include:

    • MIM
    • FeeRateModel and FeeRateImplementation
    • BlastTokenRegistry
    • SPELL

    Some of these contracts will accrue a large amount of gas yields, for instance MIM will accrue gas yields upon every transfer, approval etc… and the FeeRateModel and FeeRateImplementation will accrue gas yields on every swap in the Mimswap system.

    Recommendation

    Consider implementing gas yield claiming logic for these contracts.

    Resolution

    Abracadabra Team: Partially Resolved as MIM will not be redeployed.

  6. H-05 High Native Yield Token Yields Cannot Be Configured After Deployment DoS Resolved
    Location
    IBlast.sol: 82

    Description

    In the IERC20Rebasing interface the configure function is defined to return a YieldMode enum value. However the actual native yield precompiles will return a uint256 representing the balance of the user: ERC20Rebasing.

    As a result any call to the BlastYields.enableTokenClaimable function will fail when the contract’s balance is nonzero (or above 2 wei) as the result will not correctly correspond to an enum value. Therefore the configuration cannot be updated after deployment, or deployment could even be prevented if a malicious actor sends a few wei of the native yield token to the target address.

    Recommendation

    Correct the IERC20Rebasing interface to return a uint256 value from the configure function rather than a YieldMode enum value.

    Resolution

    Abracadabra Team: Resolved.

  7. M-01 Medium Risk Of Function Selector And Storage Collision Best Practices Acknowledged
    Location
    BlastOnboarding.sol

    Description

    The BlastOnboarding contract is itself a proxy, however it has several declared storage variables and functions. As a result the contract is prone to storage and function selector collision.

    Recommendation

    Any bootstrapper implementation that is used in the future should be rigorously verified to have no collisions with the existing function selectors or storage slots in the BlastOnboarding contract.

    Resolution

    Abracadabra Team: Acknowledged.

  8. M-02 Medium Predictable MagicLP Salt Gaming Resolved
    Location
    Factory.sol

    Description

    The salt used to deploy the new MagicLP contract in the factory is based upon replicable values that any malicious user may pass in.

    This way a malicious actor may observe two transactions in the mempool and intentionally get their transaction ordered between them. Transaction 1: Create pool at address A Transaction 2: Send additional funds to pool at address A

    The attacker may create the exact same pool at address A and end up with the funds in their pool. Currently there is no high impact risk as the owner of the clone does not have any special privileges, but this may be unexpected for the user creating the pool.

    Recommendation

    Consider including the msg.sender in the salt for pool creation.

    Resolution

    Abracadabra Team: Resolved.

  9. M-03 Medium previewAddLiquidity Disagrees With _adjustLiquidity Logical Error Resolved
    Location
    Router.sol: 492, 493

    Description

    In the _adjustAddLiquidity function the baseAdjustedInAmount and quoteAdjustedInAmount are adjusted without considering tokens that may be sitting in the MagicLP contract and unaccounted for in the reserves.

    Therefore the result from _adjustAddLiquidity contradicts the result retrieved from previewAddLiquidity when there are excess tokens sitting in the MagicLP contract as the previewAddLiquidity function accounts for the current token balance of the lp contract.

    As a result in some cases the resulting baseAdjustedInAmount and quoteAdjustedInAmount users would expect to pay using the previewAddLiquidity function will not line up with the baseAdjustedInAmount and quoteAdjustedInAmount that are paid in actuality.

    Recommendation

    Consider accounting for any additional tokens in the lp contract to match the behavior of the previewAddLiquidity function.

    Resolution

    Abracadabra Team: previewAddLiquidity has been removed.

  10. M-04 Medium Blast Point Remunerations May Be Gamed Gaming Resolved
    Location
    Global

    Description

    In the BlastOnboarding contract users may deposit their token balances and will be remunerated with the points they would have otherwise received if they didn't deposit into the contract. These point remunerations will occur off-chain at undisclosed times.

    However if a user is able to predict, recognize a pattern, or guess within a reasonable range when the distributions will occur they could deposit before the distribution and withdraw after the distribution to receive more Blast Points than they otherwise would have by simply depositing into the BlastOnboarding contract for the entire period or simply holding the native yield tokens for the entire period.

    The same may occur with a malicious Liquidity Provider for the MagicLP contract.

    Recommendation

    In the case of the BlastOnboarding contract, consider requiring that users have locked amounts to reward them with point distributions. Otherwise ensure there is no way for users to predict when the off-chain point remuneration will occur.

    Resolution

    Abracadabra Team: Resolved.

  11. M-05 Medium Disabled Native Yield Tokens Cause Loss Of Funds Unexpected Behavior Acknowledged
    Location
    BlastBox.sol

    Description

    If the owner does not want to enable native yield for a token with function setTokenEnabled, that token will have the default mode which is AUTOMATIC for WETH and USDB. When a token is in AUTOMATIC mode, the balance of the token in the contract increases as yield is gained. However, the DegenBox contract is unable to support rebasing tokens:

    /// @notice The BentoBox is a vault for tokens. The stored tokens can be flash loaned and used in strategies. /// Yield from this will go to the token depositors. /// Rebasing tokens ARE NOT supported and WILL cause loss of funds. /// Any funds transfered directly onto the BentoBox will be lost, use the deposit function instead.

    As per the comment above, rebasing tokens are not compatible with the DegenBox and will cause loss of funds.

    Recommendation

    Consider adding feature that allows the owner to set token yield mode to VOID to ensure compatibility when the owner does not want token yield enabled.

    Resolution

    Abracadabra Team: Acknowledged.

  12. M-06 Medium Lacking LP Validations Allows For Malicious Intent Validation Resolved
    Location
    Router.sol

    Description

    Anyone can create a pool with the same base/quote tokens as well as the same params (i, k) as an 'official' MIMSwap pool. An attacker could create such pools to steal liquidity away, or even worse implement such pools with rug pull functions.

    Since the Router does not validate the lp address, router functions can be used to interact with these malicious LPs. Attackers may interact with router functions intentionally to populate etherscan with transactions to their malicious pool.

    Users who see this may check the pool and see that the base/quote token and other params are correct, and end up interacting with that LP instead of the official one. In fact, there may not even be an official lp yet, i.e. attackers frontrun the creation of the LP once they know the address of the base/quote tokens. This often happens when a memecoin is launched with no frontend or official site stating the correct lp address.

    Recommendation

    In the Router contract, validate the lp address against the pools mapping in the Factory before allowing the function to continue executing.

    Resolution

    Abracadabra Team: Resolved.

  13. M-07 Medium Governor Contract Does Not Configure Blast Points Unexpected Behavior Resolved
    Location
    BlastGovernor.sol

    Description

    The blast governor contract does not configure blast points, this will cause the contract to miss out on points that can later be used to receive an airdrop of tokens from blast.

    “Blast Points are distributed automatically every block to EOAs and smart contracts based on their balance of ETH, WETH, and USDB. Specifically, EOAs and smart contracts earn Points at a rate of 0.06504987 Points/Block/ETH (around 0.03252493376 Points/second/ETH).”

    Since the contract is meant to hold eth as it collects yields from other contracts, it will not be able to accrue points based on its eth balance.

    Recommendation

    Add a call to blast points configure function to allow the governor contract's points to be harvested. Add this to constructor BlastPoints.configure();

    Resolution

    Abracadabra Team: Resolved.

  14. L-01 Low Unable To Maximize Gas Yields Optimization Resolved
    Location
    Global

    Description

    In the BlastBox and BlastMagicLP contracts the single claimYields function claims both gas yields as well as ETH, WETH, USDB yields.

    However the gas yields take 30-days to reach the maximum yield rate, documented here: Receive and claim gas fees - Blast Developer Documentation

    As a result, the protocol may wish to have more granular control over the claiming of yields, so as the let the gas yields continue to accrue at the optimal rate.

    Recommendation

    Consider separating the claimYields function into two functions where one can be used to claim ETH, WETH, and USDB yields while another can be used to claim specifically gas yields.

    Resolution

    Abracadabra Team: Resolved.

  15. L-02 Low Typo Typo Resolved
    Location
    MagicLP.sol: 369

    Description

    In the comment on line 369, the word occurring is misspelled as “occuring”.

    Recommendation

    Replace “occuring” with occurring.

    Resolution

    Abracadabra Team: Resolved.

  16. L-03 Low Lacking Zero Address Validation Best Practices Resolved
    Location
    BlastGovernor.sol: 38

    Description

    In the setFeeTo function there is no validation that the _feeTo address is nonzero.

    Recommendation

    Add validation that the feeTo address cannot be assigned to 0.

    Resolution

    Abracadabra Team: Resolved.

  17. L-04 Low Potentially Unexpected Pool Creator Recorded Unexpected Behavior Resolved
    Location
    Factory.sol: 82

    Description

    When deploying a new MagicLP pool through the Router.createPool or Router.createPoolETH functions, the creator of the pool will be recorded as the Router contract, with the pool being added to the userPools mapping entry for the router contract.

    This may be unexpected as the user who creates the pool through the router would expect to find the newly created pool in their userPools mapping entry, however this new pool will instead be under the router’s userPools mapping entry.

    Recommendation

    Consider if this is expected behavior or not. If the original creator of the pool ought to be recorded, then consider creating a dedicated function for the Router to be able to pass along the address of the user who created the pool through the Router contract.

    Resolution

    Abracadabra Team: Resolved.

  18. L-05 Low Lacking SafeCast Validation Resolved
    Location
    MagicLP.sol: 356, 405

    Description

    In the buyShares and sellShares functions token amounts are casted to uint112 variables for the BASE_TARGET and QUOTE_TARGET, however this casting should make use of the SafeCastLib as is used in the _sync and _setReserve functions to avoid any potential issues for tokens which have a supply in the quadrillions.

    Recommendation

    Use the SafeCastLib when casting token amounts to uint112 variables in the buyShares and sellShares functions.

    Resolution

    Abracadabra Team: Resolved.

  19. L-06 Low Quote Target Rounded To 0 DoS Resolved
    Location
    MagicLP.sol: 379

    Description

    In the buyShares function the _QUOTE_TARGET_ may be rounded to 0 when the quote token has less decimals than the base token. As a result swapping via sellBase will initially be DoS'ed as it relies upon the _SolveQuadraticFunctionForTrade while using the quote target as V0, since R is initially assigned to 1.

    Ultimately _SolveQuadraticFunctionForTrade reverts when V0 is 0, causing the DoS on sellBase. This state can be resolved by either depositing more liquidity or correcting the R state so the formula no longer relies on quote token amounts with the correctRState function.

    Recommendation

    Consider removing this edge case entirely by reverting when the _QUOTE_TARGET_ rounds to 0 when adding initial liquidity with the buyShares function.

    Resolution

    Abracadabra Team: Resolved.

  20. L-07 Low previewAddLiquidity Can Give Inaccurate Results Unexpected Behavior Resolved
    Location
    Router.sol: 117-128

    Description

    In the previewAddLiquidity function, it is possible for the function to return a baseAdjustedInAmount, quoteAdjustedInAmount, and shares combination that cannot be achieved as a result of rounding when assigning the adjusted amounts. For example:

    • totalSupply = 10e18
    • baseReserve = 10e18
    • quoteReserve = 10e6
    • baseInput = 1000000000000000010 (1e18 + 10)
    • quoteInput = 1000010 (1e6 + 10, quote token is USDC)
    • baseInputRatio = (1e18 + 10) * 1e18 / 10e18 = 1e17 + 1
    • quoteInputRatio = (1e6 + 10) * 1e18 / 10e6 = 1e17 + 1e12
    • baseAdjustedInAmount = baseInput = 1e18 + 1
    • quoteAdjustedInAmount = 10e6 * 1e17+1 / 1e18 = 1000000 (1e6)
    • shares = totalSupply * (1e17 + 1) / 1e18 = 1e18 + 10

    The new baseInputRatio is now larger than the quoteInputRatio as a result of the re-assignment, therefore when these new adjusted values are used to provide liquidity, the minimum of the two input ratios will be different. The minimum will now be the quoteInputRatio of 1e17 rather than the baseInputRatio of 1e17+1.

    As a result the shares that are received from using these adjusted inputs will actually be 1e18, rather than 1e18 + 10. Users who set their minimumShares to the result of the previewAddLiquidity function will have their transactions revert.

    Recommendation

    Consider whether this inaccuracy is acceptable, if it is be sure to clearly document it for users and integrating protocols. If it is not, consider using mulCeil instead of mulFloor, as this would result in user's overspending by a few wei while minting liquidity in these cases, but maintain the fidelity of the preview.

    Resolution

    Abracadabra Team: Resolved.

  21. L-08 Low System Incompatible With Esoteric Token Pairs Documentation Resolved
    Location
    Global

    Description

    The system represents the target price using 1e18 * quoteToken / baseToken, however when the quoteToken has 1e6 decimals (e.g. usdt) and the baseToken has 1e24 decimals (e.g. YamV2) calculations involving I and even computing I may lead to significant precision loss.

    Recommendation

    Be sure to document that the system is not designed to be compatible with quoteTokens and baseTokens that have a large decimal difference. Ideally the quoteToken is always the token with higher decimals.

    Resolution

    Abracadabra Team: Resolved.

  22. L-09 Low Self-Governed Contracts Cannot Change Configuration Documentation Resolved
    Location
    Global

    Description

    Upon BlastBox and BlastMagicLP deployment/initialization, the yield is configured to be in claimable mode, as well as the governor for the contract is set to be the contract itself as part of the configureDefaultClaimables function call: governorMap[msg.sender] = governor;

    To update the governor or change the yield mode, it would require a call to functions configureContract or configureGovernor on the Blast yield contract, although the above mentioned contracts do not have any methods that support doing so.

    Recommendation

    Document and be aware that since address(this) is the address of the governor, no further Blast configuration can be performed.

    Resolution

    Abracadabra Team: Resolved.

  23. L-10 Low Potential Read-Only Reentrancy Reentrancy Resolved
    Location
    MagicLP.sol: 224, 228

    Description

    The getQuoteInput and getBaseInput functions rely on the balance of the MagicLP contract, which can be manipulated with the use of the flashLoan function.

    The flashLoan function will pass off control of the current tx to an arbitrary to address after sending tokens, e.g. adjusting the balance, and before the user adequately pays for those tokens. The same balance reliance exists for the previewAddLiquidity and previewRemoveLiquidity functions on the Router contract as well.

    This poses a potential read-only risk for protocols that may choose to integrate with the MagicLP system and rely on the previewAddLiquidity, previewRemoveLiquidity, getQuoteInput and getBaseInput functions.

    Recommendation

    Be sure to carefully document these risks for integrating parties, otherwise explicitly implement the nonReadReentrant modifier from the Solady library to remove this attack surface.

    https://github.com/Vectorized/solady/blob/ec85d4a731c5f69aaa9a324d673f92dac0c29593/src/ut

    ils/ReentrancyGuard.sol#L45

    Resolution

    Abracadabra Team: Resolved.

  24. L-11 Low BlastCauldron Master Contract Can Be Initialized Unexpected Behavior Resolved
    Location
    Router.sol: 62, 79

    Description

    Currently there is no mechanism to prevent the initialization of the BlastCauldron master contract. While this poses no immediate risks, it may yield unexpected edge cases in the future.

    Recommendation

    Consider implementing validation that does not allow the BlastCauldron master contract to be initialized.

    Resolution

    Abracadabra Team: Resolved.

  25. L-12 Low BlastOnboarding DoS For Max Transfer Tokens DoS Acknowledged
    Location
    BlastOnBoarding.sol

    Description

    Some tokens allow users to transfer their entire balance by specifying type(uint256).max as the transfer amount. In such a case where the first user to deposit provides type(uint256).max as an amount parameter to deposit, the totals mapping entry for that token will become the maximum for the uint256 type and therefore no other users will be allowed to onboard new tokens.

    Recommendation

    There are no known tokens with this behavior on the Blast network currently, however this should be carefully considered when supporting new tokens for the BlastOnboarding contract.

    Resolution

    Abracadabra Team: Acknowledged.

  26. L-13 Low Blast Points Address Configured For Testnet Warning Resolved
    Location
    BlastPoints.sol

    Description

    In the library BlastPoints, the BLAST_POINTS address is hard coded to the testnet implementation. IBlastPoints public constant BLAST_POINTS = IBlastPoints(0x2fc95838c71e76ec69ff817983BFf17c710F34E0);

    Recommendation

    Be sure to update this address for mainnet deployment.

    Resolution

    Abracadabra Team: Resolved.

  27. L-14 Low Potential Reentrancy Risk Reentrancy Acknowledged
    Location
    Router.sol

    Description

    In the Router contract, addLiquidityETH function, a refund of unused ETH is done before transferring token and addLiquidity which opens up the possibility of reentrancy attacks.

    Recommendation

    While no attack path was found, it is best to follow CEI pattern and move the refund of ETH to the last action in the function.

    Resolution

    Abracadabra Team: Acknowledged.

  28. L-15 Low BlastCauldronV4 Deployment Bricked DoS Acknowledged
    Location
    BlastWrappers.sol: 59

    Description

    When a new BlastCauldronV4 is deployed, a malicious actor may front-run the init function and use the cook function to trigger an ACTION_CALL to the Blast yields contract that will configure a malicious governor for the Cauldron. As a result the cauldron deployment will then be unusable as the call to init will revert upon attempting to call BlastYields.configureDefaultClaimables.

    Recommendation

    Be aware of this risk during deployments and consider always initializing a cauldron in the same transaction in which it is deployed.

    Resolution

    Abracadabra Team: Acknowledged.

Invariants 25

The review's fuzzing suite asserted 25 invariants. 22 held and 3 did not.

Every invariant tested
IDInvariantResult
GENERAL-01Does not silent revertHeld
LIQ-01If the base and quote token balance is 0, the amount of base tokens and quote tokens in the pool is always strictly increasing after adding liquidityHeld
LIQ-02If the base and quote token balance is 0, the amount of base and quote tokens of the user is always strictly decreasing after adding liquidityHeld
LIQ-03The total supply of lp tokens is always strictly increasing after adding liquidityHeld
LIQ-04The lp token balance of the user is always strictly increasing after adding liquidityHeld
LIQ-05The amount of base tokens and quote tokens in the pool is always decreasing after removing liquidityHeld
LIQ-06The amount of base and quote tokens of the user is always increasing after removing liquidityHeld
LIQ-07The total supply of lp tokens is always strictly decreasing after removing liquidityHeld
LIQ-08The lp token balance of the user is always strictly decreasing after removing liquidityHeld
LIQ-09Base and quote tokens are never transfered to the user for free when removing liquidityHeld
LIQ-10previewAddLiquidity() never reverts for reasonable valuesHeld
LIQ-11previewRemoveLiquidity() never reverts for reasonable values if the total supply of lp tokens is greater than 0Held
LIQ-12Adding liquidity must provide less or equal shares to the user predicted by previewAddLiquidity()Broken
LIQ-13Adding liquidity unsafe must provide exact shares to the user predicted by previewAddLiquidity()Broken
LIQ-14Removing liquidity must provide the same amount of base and quote tokens to the user predicted by previewRemoveLiquidity()Held
RES-01If the quote reserve and base reserve of a pool is 0, then the lp total supply must be 0Held
RES-02The base reserve of a pool is always less than or equal to the pool base balanceHeld
RES-03The quote reserve of a pool is always less than or equal to the pool quote balanceHeld
POOL-01The sum of the LP token balances held by each user is always equal to the total supply of LP tokensHeld
POOL-02sync() must never revertBroken
POOL-03correctRState() must never revertHeld
POOL-04The total supply of LP tokens is either 0 or always greater or equal to 1001Held
SWAP-01Swap must decrease the input token balance of the user if the input and output token are differentHeld
SWAP-02Swap must increase the output token balance of the user if the input and output token are differentHeld
SWAP-03The swap must credit the user with an amount of the output token that is equal to or greater than the specified minimumOutHeld

More from Abracadabra Money

  1. MultiRewards

    15 findings1 high 15 findings: 1 high, 3 medium, 11 low
  2. GMX V2 Cauldron

    18 findings2 critical · 2 high 18 findings: 2 critical, 2 high, 10 medium, 4 low

Put your code through the same review.

This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.

Get a quote