We audited the USDC Gateway changes from the scroll-tech/scroll repository at commit f6894bb.
contracts
└── src
├── L1
│ ├── gateways
│ │ ├── L1ERC20Gateway.sol
│ │ └── usdc
│ │ └── L1USDCGateway.sol
├── L2
│ ├── gateways
│ │ └── usdc
│ │ └── L2USDCGateway.sol
├── interfaces
│ ├── L2USDCGateway.sol
│ ├── ITokenMessenger.sol
│ ├── IMessangerTransmitter.sol
│ ├── IUSDCBurnableSourceBrdge.sol
│ ├── IUSDCDestinationBridge.sol
└─── libraries
└── gateway
└── CCTPGatewayBase.sol
Scroll is an EVM-equivalent ZK-rollup designed to be a scaling solution for Ethereum. It achieves this by interpreting EVM bytecode directly at the bytecode level, following a similar path to projects like Polygon's zkEVM and Consensys' Linea.
This audit reviewed the extension of the special USDC Gateway from the scroll protocol.
This report presents our findings and recommendations for the new additions to the Scroll ZK-rollup protocol. We urge the Scroll team to consider these findings in their ongoing efforts to provide a secure and efficient Layer 2 solution for Ethereum.
It is assumed that the USDC
contract to be deployed in the Scroll Layer 2 Network will be identical to the one deployed in the Ethereum Mainnet.
Certain privileged roles within the Scroll protocol were identified during the audit. These roles possess special permissions that could potentially impact the system's operation:
ScrollOwner
: The default admin role can grant roles for addresses to execute functions through the contract. Every role will be associated with a designated set of functions tied to specific addresses permissible to execute within that role. Moreover, existing roles will come with execution delays ranging from 0 days for instant execution to 1 day, 7 days, and 14 days. This provides a dynamic control mechanism over the timing of function execution based on their respective impact levels.TokenRateLimiter
: The default admin role can update the total token amount limit. The admin can also grant a token spender role for the Scroll gateways and messengers to ensure a rate limit when depositing or withdrawing funds.Implementation Owners: Most contracts are also ownable. The following actions describe what the owner can do in each contract.
L1ScrollMessenger
: Pause the relay of L2 to L1 messages and L1 to L2 message requests.EnforcedTxGateway
: Pause L1 to L2 transaction requests and change the fee vault.L1{CustomERC20|ERC721|ERC1155}Gateway
: Change the token mapping containing which L1 token is bridged to which L2 token.L1GatewayRouter
: Set the respective gateway for ETH, custom ERC-20s and default ERC-20s.ScrollMessengerBase
: Change the fee vault address which collects fees for message relaying.ScrollStandardERC20Factory
: Use the factory to deploy another instance of a standard ERC-20 token on L2.L2ScrollMessenger
: Pause the relay of L1 to L2 messages and L2 to L1 message requests.L2{CustomERC20|ERC721|ERC1155}Gateway
: Change the token mapping containing which L2 token is bridged to which L1 token.L2GatewayRouter
: Set the respective gateway for ETH, custom ERC-20s and default ERC-20s.USDC: The following roles are present in the USDC
contract:
owner
: This role can transfer ownership of the contract and grant or remove the masterMinter
, pauser
and blacklister
roles.
masterMinter
: This role can create new minters and assign allowances to existing minters.
pauser
: This role has the ability to pause and unpause the contract.
blacklister
: This role can add or remove addresses from a blacklist, which if added would prevent that address from transferring or receiving USDC
.
minter
: This role allows the minting of tokens up to each minter's allowance.
Each of these roles presents a unique set of permissions within the Scroll protocol. The potential implications of these permissions warrant further consideration and mitigation to ensure the system’s security and robustness.
L2USDCGateway
Is Missing Rate Limiter FunctionalityThe L1USDCGateway
contract inherits from L1ERC20Gateway
. When a user initiates a deposit, the _transferERC20In
function is called, which in turn invokes the rate limiter function _addUsedAmount
. However, the L2USDCGateway
contract inherits from L2ERC20Gateway
which does not call the rate limiter _addUsedAmount
function. This means that USDC withdrawals will not be subject to rate limiting.
Consider ensuring that _addUsedAmount
is called when users make a withdrawal in USDC.
Update: Resolved in pull request #927 at commit be6d404.
The comment in line 172 of the L2USDCGateway
contract should say L2ScrollMessenger
instead of L1ScrollMessenger
.
Consider resolving this instance of incorrect documentation to improve the clarity and readability of the codebase.
Update: Resolved in pull request #928 at commit 733d2a6.
gap
VariableThe CCTPGatewayBase
contract does not contain a gap variable although it is upgradeable.
Consider adding a gap variable following OpenZeppelin's upgradeable contracts guide to avoid future storage collisions.
Update: Resolved in pull request #929 at commit 5e61a05.
Throughout the codebase there are several parts that do not have docstrings. For instance:
L1ERC20Gateway.sol
L2USDCGateway.sol
IMessageTransmitter.sol
IMessageTransmitter.sol
ITokenMessenger.sol
IUSDCBurnableSourceBridge.sol
IUSDCDestinationBridge.sol
CCTPGatewayBase.sol
Consider thoroughly documenting all functions (and their parameters) that are part of any contract's public API. Functions implementing sensitive functionality, even if not public, should be clearly documented. When writing docstrings, consider following the Ethereum Natural Specification Format (NatSpec).
Update: Resolved in pull request #940 at commit 30fa5e6.
Throughout the codebase there are imports that are unused and could be removed. For instance:
IScrollMessenger
of L1ERC20Gateway.sol
ScrollConstants
of L1ERC20Gateway.sol
OwnableUpgradeable
of L1USDCGateway.sol
IERC20Upgradeable
of L1USDCGateway.sol
IL1ERC20Gateway
of L1USDCGateway.sol
IL2ERC20Gateway
of L2USDCGateway.sol
IScrollGateway
of L2USDCGateway.sol
Consider removing unused imports to improve the overall clarity and readability of the codebase.
Update: Partially resolved in pull request #930 at commit 23bf84a. L1USDCGateway.sol
still imports IL1ERC20Gateway
and L2USDCGateway.sol
still imports IL2ERC20Gateway
.
Throughout this 4-day audit, we reviewed both L1 and L2 USDC gateways. We identified a single medium-severity issue, as well as a few low-severity issues and additional notes. Overall, we commend the quality and thoughtful integration of the USDC gateway. The auditing process was seamless, and we appreciate the Scroll team's prompt responses to our inquiries throughout the process.