As explained in the L2 migration video walkthrough provided by Beanstalk, in-order to curb the issue where not the same user controls their account on different chains so as to ensure no attacker front runs the migration by creating (a matching account on the L2 to steal the users migrated beans, Beanstalk now requires that users first sign their transactions with the wanted receiver before allowing a contract that owns deposits and bean-asset internal balances to redeem onto an address on L2.
Issue is that, Beanstalk uses EIP 712 to make and verify these signatures, which would not work completely for the intended use, considering Beanstalk expects contracts to make these signatures (not just EOAs), but EIP712 does not work well with smart contracts or wallets and as such only EOAs integrating with Beanstalk are ensured to be able to migrate, where as other (non-EOA) users are not.
Take a look at https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/8c8710df547f7d7c5dd82c5381eb6b34532e4484/protocol/contracts/beanstalk/silo/L2ContractMigrationFacet.sol#L88-L114
This function is called when a contract that owns bean-asset internal balances is to redeem onto an address on L2, now it queries verifySignature()
that's implemented this way: https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/8c8710df547f7d7c5dd82c5381eb6b34532e4484/protocol/contracts/beanstalk/silo/L2ContractMigrationFacet.sol#L136-L151
Note that these signatures are expected to be verified for hashed data using EIP712, i.e https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/8c8710df547f7d7c5dd82c5381eb6b34532e4484/protocol/contracts/beanstalk/silo/L2ContractMigrationFacet.sol#L223-L226
Problem However is that some users would not be able to access this functionality as valid signatures from them wouldn't work since they can't work with EIP 712.
According to EIP1271: Standard Signature Validation Method for Contracts:
Externally Owned Accounts (EOA) can sign messages with their associated private keys, but currently contracts cannot. We propose a standard way for any contracts to verify whether a signature on a behalf of a given contract is valid. This is possible via the implementation of a
isValidSignature(hash, signature)
function on the signing contract, which can be called to validate a signature.
So while recovering a valid message signed by these set of users , the return value will be the bytes4(0)
for any vote signed by a contract (e.g. Multisig) because contracts that sign messages sticking to the EIP1271 standard use the EIP1271_MAGIC_VALUE
as the successful return for a properly recovered signature. A sample of this is shown within the EIP1271 and also within CompatibilityFallbackHandler by GnosisSafe.
As a result of this scenario, these set of users would not be able to migrate their Beans even though they produced valid signatures.
Some users would have their Beans stuck on the L1 even if they want to migrate to the L2 due to the current signature used with the migration logic.
Manual review
Consider adding contract signature support by implementing a recovery via the suggested isValidSignature()
function of the EIP1271
and comparing the recovered value against the MAGIC_VALUE
.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.