Summary
According to contest page, the protocol is EIP-7201 compatible, however, not all the contracts' storage layouts follow the rule.
Vulnerability Details
According to EIP-7201 Specification, contract slot should be defined as erc7201(id: string) = keccak256(keccak256(id) - 1) & ~0xff
. In Solidity, this corresponds to the expression keccak256(abi.encode(uint256(keccak256(bytes(id))) - 1)) & ~bytes32(uint256(0xff))
, however, Referral and CustomReferralConfiguration do not follow the specification.
Referral.sol:
library Referral {
@> string internal constant REFERRAL_DOMAIN = "fi.zaros.Referral";
function load(address accountOwner) internal pure returns (Data storage referralTestnet) {
@> bytes32 slot = keccak256(abi.encode(REFERRAL_DOMAIN, accountOwner));
assembly {
referralTestnet.slot := slot
}
}
}
CustomReferralConfiguration.sol
library CustomReferralConfiguration {
@> string internal constant CUSTOM_REFERRAL_CONFIGURATION_DOMAIN = "fi.zaros.CustomReferralConfiguration";
function load(string memory customReferralCode)
internal
pure
returns (Data storage customReferralConfigurationTestnet)
{
@> bytes32 slot = keccak256(abi.encode(CUSTOM_REFERRAL_CONFIGURATION_DOMAIN, customReferralCode));
assembly {
customReferralConfigurationTestnet.slot := slot
}
}
}
Impact
The protocol is expected to be EIP-7201 compatible, contracts are prone to storage collision if not follow the specification.
Tools Used
Manual Review
Recommendations
Referral.sol:
- string internal constant REFERRAL_DOMAIN = "fi.zaros.Referral";
+ string internal constant REFERRAL_DOMAIN = keccak256(abi.encode(uint256(keccak256("fi.zaros.Referral")) - 1)) & ~bytes32(uint256(0xff));
CustomReferralConfiguration.sol
- string internal constant CUSTOM_REFERRAL_CONFIGURATION_DOMAIN = "fi.zaros.CustomReferralConfiguration";
+ string internal constant CUSTOM_REFERRAL_CONFIGURATION_DOMAIN = keccak256(abi.encode(uint256(keccak256("fi.zaros.CustomReferralConfiguration")) - 1)) & ~bytes32(uint256(0xff));