Summary
The deployWithFactory function does not send user's ether to the factory contract locking ether inside BiconomyMetaFactory.
Root Cause
https://github.com/Cyfrin/2024-07-biconomy/blob/9590f25cd63f7ad2c54feb618036984774f3879d/contracts/factory/BiconomyMetaFactory.sol#L72
The deployWithFactory calls factory address with low-level call but it does not send msg.value. BiconomyMetaFactory does not have any ether recovery mechanism which means that all of the user's ether will be locked forever.
function deployWithFactory(address factory, bytes calldata factoryData) external payable returns (address payable createdAccount) {
require(factoryWhitelist[address(factory)], FactoryNotWhitelisted());
(bool success, bytes memory returnData) = factory.call(factoryData);
require(success, CallToDeployWithFactoryFailed());
assembly {
createdAccount := mload(add(returnData, 0x20))
}
}
Impact
User will lose all of the send ether using deployWithFactory.
Mitigation
Send msg.value to factory with low-level call.
Example pseudocode:
function deployWithFactory(address factory, bytes calldata factoryData) external payable returns (address payable createdAccount) {
require(factoryWhitelist[address(factory)], FactoryNotWhitelisted());
- (bool success, bytes memory returnData) = factory.call(factoryData);
+ (bool success, bytes memory returnData) = factory.call{value: msg.value}(factoryData);
// Check if the call was successful
require(success, CallToDeployWithFactoryFailed());
// Decode the returned address
assembly {
createdAccount := mload(add(returnData, 0x20))
}
}