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
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
-
C-01 Critical Claiming Yield DoS DoS Resolved
Description
The
BlastMagicLPandBlastOnboardingcontracts 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 theBlastYields.claimAllNativeYieldsfunction.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
Recommendation
Either do not invoke the
claimAllNativeYieldsfunction 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.
-
H-01 High Weth Transferred From The Wrong Address Logical Error Resolved
Description
In the
Router.createPoolETHfunction, a deposit to the weth contract is made but then a subsequent wethsafeTransferFromis made from themsg.senderto 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
safeTransferFromto transfer from theRoutercontract to the newly created pool rather than from themsg.sender.Resolution
Abracadabra Team: Resolved.
-
H-02 High twapUpdate Overflow DoS DoS Resolved
Description
In MagicLP.sol,
_twapUpdateis called every timesetReserveorsyncis 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 oftype.uint256.However for
MagicLPwhich uses a newer solidity version, this cannot overflow and all contract functionality will be bricked.Recommendation
Wrap with an
uncheckedblock to allow for overflow.Resolution
Abracadabra Team: Resolved.
-
H-03 High previewAddLiquidity Incorrect quoteBalance Logical Error Resolved
Description
In the
previewAddLiquidityfunction thequoteBalanceis 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 thequoteBalanceis the balance of quote tokens + thebaseInAmount: uint256 quoteBalance = IMagicLP(lp)._QUOTE_TOKEN_().balanceOf(address(lp)) + baseInAmount;Recommendation
Correct the
quoteBalanceto be: uint256 quoteBalance = IMagicLP(lp)._QUOTE_TOKEN_().balanceOf(address(lp)) + quoteInAmount;Resolution
Abracadabra Team: Resolved.
-
H-04 High Lacking Gas Yields Claiming Logic Logical Error Partially resolved
Description
There are several contracts in the Abracadabra and Mimswap systems that cannot claim gas yields as they accrue. These contracts include:
MIMFeeRateModelandFeeRateImplementationBlastTokenRegistrySPELL
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
FeeRateModelandFeeRateImplementationwill 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.
-
H-05 High Native Yield Token Yields Cannot Be Configured After Deployment DoS Resolved
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
IERC20Rebasinginterface to return auint256value from the configure function rather than aYieldModeenum value.Resolution
Abracadabra Team: Resolved.
-
M-01 Medium Risk Of Function Selector And Storage Collision Best Practices Acknowledged
Description
The
BlastOnboardingcontract 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
bootstrapperimplementation that is used in the future should be rigorously verified to have no collisions with the existing function selectors or storage slots in theBlastOnboardingcontract.Resolution
Abracadabra Team: Acknowledged.
-
M-02 Medium Predictable MagicLP Salt Gaming Resolved
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.
-
M-03 Medium previewAddLiquidity Disagrees With _adjustLiquidity Logical Error Resolved
Description
In the
_adjustAddLiquidityfunction thebaseAdjustedInAmountandquoteAdjustedInAmountare adjusted without considering tokens that may be sitting in theMagicLPcontract and unaccounted for in the reserves.Therefore the result from
_adjustAddLiquiditycontradicts the result retrieved frompreviewAddLiquiditywhen there are excess tokens sitting in theMagicLPcontract as thepreviewAddLiquidityfunction accounts for the current token balance of the lp contract.As a result in some cases the resulting
baseAdjustedInAmountandquoteAdjustedInAmountusers would expect to pay using thepreviewAddLiquidityfunction will not line up with thebaseAdjustedInAmountandquoteAdjustedInAmountthat are paid in actuality.Recommendation
Consider accounting for any additional tokens in the lp contract to match the behavior of the
previewAddLiquidityfunction.Resolution
Abracadabra Team: previewAddLiquidity has been removed.
-
M-04 Medium Blast Point Remunerations May Be Gamed Gaming Resolved
Description
In the
BlastOnboardingcontract 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
BlastOnboardingcontract 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
MagicLPcontract.Recommendation
In the case of the
BlastOnboardingcontract, 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.
-
M-05 Medium Disabled Native Yield Tokens Cause Loss Of Funds Unexpected Behavior Acknowledged
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.
-
M-06 Medium Lacking LP Validations Allows For Malicious Intent Validation Resolved
Description
Anyone can create a pool with the same base/quote tokens as well as the same params (i, k) as an 'official'
MIMSwappool. An attacker could create such pools to steal liquidity away, or even worse implement such pools with rug pull functions.Since the
Routerdoes 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
Routercontract, validate the lp address against thepoolsmapping in theFactorybefore allowing the function to continue executing.Resolution
Abracadabra Team: Resolved.
-
M-07 Medium Governor Contract Does Not Configure Blast Points Unexpected Behavior Resolved
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.
-
L-01 Low Unable To Maximize Gas Yields Optimization Resolved
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
claimYieldsfunction 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.
-
L-02 Low Typo Typo Resolved
Description
In the comment on line 369, the word occurring is misspelled as “occuring”.
Recommendation
Replace “occuring” with occurring.
Resolution
Abracadabra Team: Resolved.
-
L-03 Low Lacking Zero Address Validation Best Practices Resolved
Description
In the
setFeeTofunction there is no validation that the_feeToaddress is nonzero.Recommendation
Add validation that the
feeToaddress cannot be assigned to 0.Resolution
Abracadabra Team: Resolved.
-
L-04 Low Potentially Unexpected Pool Creator Recorded Unexpected Behavior Resolved
Description
When deploying a new
MagicLPpool through theRouter.createPoolorRouter.createPoolETHfunctions, the creator of the pool will be recorded as theRoutercontract, with the pool being added to theuserPoolsmapping 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
userPoolsmapping 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
Routerto be able to pass along the address of the user who created the pool through theRoutercontract.Resolution
Abracadabra Team: Resolved.
-
L-05 Low Lacking SafeCast Validation Resolved
Description
In the
buySharesandsellSharesfunctions token amounts are casted touint112variables for theBASE_TARGETandQUOTE_TARGET, however this casting should make use of theSafeCastLibas is used in the_syncand_setReservefunctions to avoid any potential issues for tokens which have a supply in the quadrillions.Recommendation
Use the
SafeCastLibwhen casting token amounts touint112variables in thebuySharesandsellSharesfunctions.Resolution
Abracadabra Team: Resolved.
-
L-06 Low Quote Target Rounded To 0 DoS Resolved
Description
In the
buySharesfunction the_QUOTE_TARGET_may be rounded to 0 when the quote token has less decimals than the base token. As a result swapping viasellBasewill initially be DoS'ed as it relies upon the_SolveQuadraticFunctionForTradewhile using the quote target as V0, since R is initially assigned to 1.Ultimately
_SolveQuadraticFunctionForTradereverts when V0 is 0, causing the DoS onsellBase. 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 thecorrectRStatefunction.Recommendation
Consider removing this edge case entirely by reverting when the
_QUOTE_TARGET_rounds to 0 when adding initial liquidity with thebuySharesfunction.Resolution
Abracadabra Team: Resolved.
-
L-07 Low previewAddLiquidity Can Give Inaccurate Results Unexpected Behavior Resolved
Description
In the
previewAddLiquidityfunction, it is possible for the function to return abaseAdjustedInAmount,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
baseInputRatiois now larger than thequoteInputRatioas 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 thequoteInputRatioof 1e17 rather than thebaseInputRatioof 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
minimumSharesto the result of thepreviewAddLiquidityfunction 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
mulCeilinstead ofmulFloor, 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.
-
L-08 Low System Incompatible With Esoteric Token Pairs Documentation Resolved
Description
The system represents the target price using
1e18 * quoteToken / baseToken, however when thequoteTokenhas 1e6 decimals (e.g. usdt) and thebaseTokenhas 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
quoteTokensandbaseTokensthat have a large decimal difference. Ideally thequoteTokenis always the token with higher decimals.Resolution
Abracadabra Team: Resolved.
-
L-09 Low Self-Governed Contracts Cannot Change Configuration Documentation Resolved
Description
Upon
BlastBoxandBlastMagicLPdeployment/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 theconfigureDefaultClaimablesfunction call:governorMap[msg.sender] = governor;To update the governor or change the yield mode, it would require a call to functions
configureContractorconfigureGovernoron 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.
-
L-10 Low Potential Read-Only Reentrancy Reentrancy Resolved
Description
The
getQuoteInputandgetBaseInputfunctions rely on the balance of theMagicLPcontract, which can be manipulated with the use of theflashLoanfunction.The
flashLoanfunction 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 thepreviewAddLiquidityandpreviewRemoveLiquidityfunctions on the Router contract as well.This poses a potential read-only risk for protocols that may choose to integrate with the
MagicLPsystem and rely on thepreviewAddLiquidity,previewRemoveLiquidity,getQuoteInputandgetBaseInputfunctions.Recommendation
Be sure to carefully document these risks for integrating parties, otherwise explicitly implement the
nonReadReentrantmodifier from the Solady library to remove this attack surface.https://github.com/Vectorized/solady/blob/ec85d4a731c5f69aaa9a324d673f92dac0c29593/src/ut
Resolution
Abracadabra Team: Resolved.
-
L-11 Low BlastCauldron Master Contract Can Be Initialized Unexpected Behavior Resolved
Description
Currently there is no mechanism to prevent the initialization of the
BlastCauldronmaster 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
BlastCauldronmaster contract to be initialized.Resolution
Abracadabra Team: Resolved.
-
L-12 Low BlastOnboarding DoS For Max Transfer Tokens DoS Acknowledged
Description
Some tokens allow users to transfer their entire balance by specifying
type(uint256).maxas the transfer amount. In such a case where the first user to deposit providestype(uint256).maxas anamountparameter todeposit, the totals mapping entry for that token will become the maximum for theuint256type 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
BlastOnboardingcontract.Resolution
Abracadabra Team: Acknowledged.
-
L-13 Low Blast Points Address Configured For Testnet Warning Resolved
Description
In the library
BlastPoints, theBLAST_POINTSaddress 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.
-
L-14 Low Potential Reentrancy Risk Reentrancy Acknowledged
Description
In the
Routercontract,addLiquidityETHfunction, a refund of unused ETH is done before transferring token andaddLiquiditywhich 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.
-
L-15 Low BlastCauldronV4 Deployment Bricked DoS Acknowledged
Description
When a new
BlastCauldronV4is deployed, a malicious actor may front-run the init function and use the cook function to trigger anACTION_CALLto the Blast yields contract that will configure a malicious governor for theCauldron. As a result the cauldron deployment will then be unusable as the call to init will revert upon attempting to callBlastYields.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.
No findings match.
Invariants 25
The review's fuzzing suite asserted 25 invariants. 22 held and 3 did not.
Every invariant tested
| ID | Invariant | Result |
|---|---|---|
GENERAL-01 | Does not silent revert | Held |
LIQ-01 | If 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 liquidity | Held |
LIQ-02 | If the base and quote token balance is 0, the amount of base and quote tokens of the user is always strictly decreasing after adding liquidity | Held |
LIQ-03 | The total supply of lp tokens is always strictly increasing after adding liquidity | Held |
LIQ-04 | The lp token balance of the user is always strictly increasing after adding liquidity | Held |
LIQ-05 | The amount of base tokens and quote tokens in the pool is always decreasing after removing liquidity | Held |
LIQ-06 | The amount of base and quote tokens of the user is always increasing after removing liquidity | Held |
LIQ-07 | The total supply of lp tokens is always strictly decreasing after removing liquidity | Held |
LIQ-08 | The lp token balance of the user is always strictly decreasing after removing liquidity | Held |
LIQ-09 | Base and quote tokens are never transfered to the user for free when removing liquidity | Held |
LIQ-10 | previewAddLiquidity() never reverts for reasonable values | Held |
LIQ-11 | previewRemoveLiquidity() never reverts for reasonable values if the total supply of lp tokens is greater than 0 | Held |
LIQ-12 | Adding liquidity must provide less or equal shares to the user predicted by previewAddLiquidity() | Broken |
LIQ-13 | Adding liquidity unsafe must provide exact shares to the user predicted by previewAddLiquidity() | Broken |
LIQ-14 | Removing liquidity must provide the same amount of base and quote tokens to the user predicted by previewRemoveLiquidity() | Held |
RES-01 | If the quote reserve and base reserve of a pool is 0, then the lp total supply must be 0 | Held |
RES-02 | The base reserve of a pool is always less than or equal to the pool base balance | Held |
RES-03 | The quote reserve of a pool is always less than or equal to the pool quote balance | Held |
POOL-01 | The sum of the LP token balances held by each user is always equal to the total supply of LP tokens | Held |
POOL-02 | sync() must never revert | Broken |
POOL-03 | correctRState() must never revert | Held |
POOL-04 | The total supply of LP tokens is either 0 or always greater or equal to 1001 | Held |
SWAP-01 | Swap must decrease the input token balance of the user if the input and output token are different | Held |
SWAP-02 | Swap must increase the output token balance of the user if the input and output token are different | Held |
SWAP-03 | The swap must credit the user with an amount of the output token that is equal to or greater than the specified minimumOut | Held |
More from Abracadabra Money
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.
