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

Security review · October 2025

Direct Transfer

for Magna

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

4 resolved · 5 acknowledged

Scope

4 files in scope · 126 nSLOC
FilenSLOCLines
src/IMagnaDirectAirdrop.sol1015
src/IMagnaDirectAirdropFactory.sol611
src/MagnaDirectAirdrop.sol90151
src/MagnaDirectAirdropFactory.sol2030

Findings 9

  1. M-01 Medium Native Token Cannot Be Airdropped DoS Resolved
    Location
    [MagnaDirectAirdrop.sol#L39](https://github.com/GuardianOrg/protocol-direct-transfer-evm-team1-1760563346287/blob/3bbb8bee6325df471801b2a97bc55c5d6fbf22b5/src/MagnaDirectAirdrop.sol#L39)

    Description

    The payableMagnaDirectAirdrop.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.value which 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 tokenBalanceBefore includes msg.value, the calculation will always underflow. In result, distributing native tokens with the contract is impossible.

    Recommendation

    Exclude the msg.value from the contract balance when taking the first snapshot.

    - uint256 tokenBalanceBefore = address(this).balance;
    + uint256 tokenBalanceBefore = address(this).balance - msg.value;
    
  2. L-01 Low Anyone Can Create Airdrops Validation Acknowledged
    Location
    [MagnaDirectAirdropFactory.sol#L18-25](https://github.com/GuardianOrg/protocol-direct-transfer-evm-team1-1760563346287/blob/3bbb8bee6325df471801b2a97bc55c5d6fbf22b5/src/MagnaDirectAirdropFactory.sol#L18-L25)

    Description

    MagnaDirectAirdropFactory.createDirectAirdropContract() is not permissioned, which allows any user to create contracts for themselves, with owner being an address chosen by them. A malicious user can DOS a factory by deploying as much contracts as needed until directAirdropContracts.length == maximumNumberOfContracts. Then nobody will be able to deploy more contracts from that factory.

    Furthermore, if maximumNumberOfContracts is set to a high value, letting anyone create contracts raises the risk of getDirectAirdropContracts() reverting because of OOG.

    Recommendation

    Consider having an owner set during deployment of the factory and allow only them to deploy contracts.

  3. I-01 Informational Maximum Number Of Contracts Not Bound Validation Resolved
    Location
    [MagnaDirectAirdropFactory.sol#L15](https://github.com/GuardianOrg/protocol-direct-transfer-evm-team1-1760563346287/blob/3bbb8bee6325df471801b2a97bc55c5d6fbf22b5/src/MagnaDirectAirdropFactory.sol#L15)

    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 an OOG revert for the getDirectAirdropContracts() function if the instances are too much and lead to reverts for third-party integrators.

    Recommendation

    Consider bounding the _maximumNumberOfContracts between 1 and an appropriate maximum value.

  4. I-02 Informational Airdrop Can Be Reverted Warning Acknowledged
    Location
    MagnaDirectAirdrop.sol

    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 airdop

    However, 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.

  5. I-03 Informational Incomplete Event Data Events Acknowledged
    Location
    MagnaDirectAirdrop.sol

    Description

    Whenever a dispersal is performed, the AirdropCompleted(idempotencyKey, msgSender) event is emitted. Only idempotencyKey and msgSender and no token are 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.

  6. I-04 Informational Unused Address Library Superfluous Code Resolved
    Location
    [MagnaDirectAirdrop.sol#L8](https://github.com/GuardianOrg/protocol-direct-transfer-evm-team1-1760563346287/blob/3bbb8bee6325df471801b2a97bc55c5d6fbf22b5/src/MagnaDirectAirdrop.sol#L8)

    Description

    The Address library from OpenZeppelin is imported in the MagnaDirectAirdrop contract, but its functionality is never used.

    Recommendation

    Remove the library from the contract.

  7. I-05 Informational Tokens With Hooks Can Be Flashloaned Warning Acknowledged
    Location
    MagnaDirectAirdrop.sol

    Description

    Any tokens with hooks staying in the contract can be flashloaned in the following way:

    • call disperseERC20Token() with yourself as the recipient, total = 0 and value = 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.

  8. I-06 Informational Empty Recipients Should Revert Error Acknowledged
    Location
    MagnaDirectAirdrop.sol

    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.

  9. I-07 Informational Inaccurate Comments Best Practices Resolved
    Location
    MagnaDirectAidrop.sol

    Description

    The following comments are not accurate:

    1. MagnaDirectAirdrop.sol#L101 - it's in the safeDisperseERC20Token() and says safeTransfer is not used which is not true. The comment was probably copied from disperseERC20Token() and forgotten.

    Recommendation

    1. Delete the comment

More from Magna

All 9 reports
  1. Staking Updates

    23 findings 23 findings: 3 low, 20 informational
  2. Airdrop Updates

    2 findings 2 findings: 1 low, 1 informational
  3. Merkle Vester

    13 findings 13 findings: 1 medium, 6 low, 6 informational
  4. Fixed and Dynamic Staking

    21 findings1 high 21 findings: 1 high, 3 medium, 17 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