Guardian's review of Direct Transfer for Magna, published October 2025. The report records 9 findings, including 1 medium and 1 low.
- Published
- Review window
- October 15 to 17, 2025
- Language
- Solidity
- Chains
- Ethereum, Base, Optimism, Polygon, Arbitrum, BNB Chain
- Sector
- Infrastructure
- 0 Critical
- 0 High
- 1 Medium
- 1 Low
- 7 Informational
Scope
4 files in scope · 126 nSLOC
| File | nSLOC | Lines |
|---|---|---|
src/IMagnaDirectAirdrop.sol | 10 | 15 |
src/IMagnaDirectAirdropFactory.sol | 6 | 11 |
src/MagnaDirectAirdrop.sol | 90 | 151 |
src/MagnaDirectAirdropFactory.sol | 20 | 30 |
Findings 9
-
M-01 Medium Native Token Cannot Be Airdropped DoS Resolved
Description
The payable
MagnaDirectAirdrop.disperseNativeToken()function should allow users to airdrop native tokens by sending them with the call.The function records the balance of the contract before assets are send, including the
msg.valuewhich should be distributed`uint256 tokenBalanceBefore = address(this).balance;Then it transfers the tokens to the recipients and finally performs the following check
require(address(this).balance - tokenBalanceBefore == 0);The idea of the check is to ensure exactly the desired amount was sent to the recipients, but because
tokenBalanceBeforeincludesmsg.value, the calculation will always underflow. In result, distributing native tokens with the contract is impossible.Recommendation
Exclude the
msg.valuefrom the contract balance when taking the first snapshot.- uint256 tokenBalanceBefore = address(this).balance; + uint256 tokenBalanceBefore = address(this).balance - msg.value; -
L-01 Low Anyone Can Create Airdrops Validation Acknowledged
Description
MagnaDirectAirdropFactory.createDirectAirdropContract()is not permissioned, which allows any user to create contracts for themselves, withownerbeing an address chosen by them. A malicious user can DOS a factory by deploying as much contracts as needed untildirectAirdropContracts.length == maximumNumberOfContracts. Then nobody will be able to deploy more contracts from that factory.Furthermore, if
maximumNumberOfContractsis set to a high value, letting anyone create contracts raises the risk ofgetDirectAirdropContracts()reverting because ofOOG.Recommendation
Consider having an owner set during deployment of the factory and allow only them to deploy contracts.
-
I-01 Informational Maximum Number Of Contracts Not Bound Validation Resolved
Description
The constructor of the factory contract accepts
maximumNumberOfContracts_parameter that's used to validate the number of created instances via this factory. Since there is no validation performed on this parameter, factories with 0 allowed contracts can be deployed. Such factories don't serve any purpose because they cannot deploy even a single contract.On the other hand, it's also possible to create a factory with
maximumNumberOfContracts_ = type(uint256.max). This can cause anOOGrevert for thegetDirectAirdropContracts()function if the instances are too much and lead to reverts for third-party integrators.Recommendation
Consider bounding the
_maximumNumberOfContractsbetween 1 and an appropriate maximum value. -
I-02 Informational Airdrop Can Be Reverted Warning Acknowledged
Description
After each airdrop dispersal, it's enforced as an invariant that all of the funds received from the sender are spent. This opens up the possibility of DOS-ing the airdrop via malicious receiver for tokens with hooks.
In
disperseNativeToken()the following is mentioned:// 1. recipients intentionally reverting should be removed from the airdopHowever, this case is slightly different because the recipient itself is not reverting, they are just sending 1 wei of the token back to the contract, which will make it seem like they were a legit recipient, while the transaction will later revert because of the following check:
require(token.balanceOf(address(this)) - tokenBalanceBefore == 0);Depending on how such failures are handled - for example, if there is an automated process which checks for recipients that caused the revert and submits the dispersal again - this behavior may cause unexpected results. The described scenario cannot happen with native tokens because the contract reverts
Recommendation
Keep that in mind when you explore reverting airdrops.
-
I-03 Informational Incomplete Event Data Events Acknowledged
Description
Whenever a dispersal is performed, the
AirdropCompleted(idempotencyKey, msgSender)event is emitted. OnlyidempotencyKeyandmsgSenderand notokenare being emitted, which may not be enough for offchain listeners to parse the dispersal. In addition, airdrops can be performed by anyone and any tokens can be supplied, so it's preferable to include the token address as well.Recommendation
Include the token address in the event emission.
-
I-04 Informational Unused
AddressLibrary Superfluous Code ResolvedDescription
The
Addresslibrary from OpenZeppelin is imported in theMagnaDirectAirdropcontract, but its functionality is never used.Recommendation
Remove the library from the contract.
-
I-05 Informational Tokens With Hooks Can Be Flashloaned Warning Acknowledged
Description
Any tokens with hooks staying in the contract can be flashloaned in the following way:
- call
disperseERC20Token()with yourself as the recipient,total = 0andvalue = token.balanceOf(contract). - Since total is 0, you don't pay anything, but receive the whole balance
- Perform some actions and return the funds
Recommendation
Document this behavior.
- call
-
I-06 Informational Empty Recipients Should Revert Error Acknowledged
Description
Each disperse function computes recipientsLength = recipients.length - 1 before validating recipients.length == values.length. When
recipients.length == 0, this underflows and reverts with a Panic error, yielding a non-descriptive failure and bypassing the intended input validation path.Recommendation
Add an explicit require(recipients.length > 0, 'Empty') (or a custom error) before subtracting 1, and then keep the existing length-equality check. This avoids unexpected Panic errors and improves diagnosability.
-
I-07 Informational Inaccurate Comments Best Practices Resolved
Description
The following comments are not accurate:
- MagnaDirectAirdrop.sol#L101 - it's in the
safeDisperseERC20Token()and sayssafeTransferis not used which is not true. The comment was probably copied fromdisperseERC20Token()and forgotten.
Recommendation
- Delete the comment
- MagnaDirectAirdrop.sol#L101 - it's in the
No findings match.
More from Magna
All 9 reportsPut 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.