diff --git a/contracts/common/Errors.sol b/contracts/common/Errors.sol index 35738f1..4e4fad2 100644 --- a/contracts/common/Errors.sol +++ b/contracts/common/Errors.sol @@ -20,6 +20,16 @@ contract SponsorshipPaymasterErrors { */ error VerifyingSignerCannotBeZero(); + /** + * @notice Throws when the paymaster id provided is a deployed contract + */ + error PaymasterIdCannotBeContract(); + + /** + * @notice Throws when the fee collector address provided is a deployed contract + */ + error FeeCollectorCannotBeContract(); + /** * @notice Throws when the fee collector address provided is address(0) */ diff --git a/contracts/libs/AddressUtils.sol b/contracts/libs/AddressUtils.sol new file mode 100644 index 0000000..43cb832 --- /dev/null +++ b/contracts/libs/AddressUtils.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + + +/** + * Utility library of inline functions on addresses + */ +library AddressUtils { + + /** + * Returns whether the target address is a contract + * @dev This function will return false if invoked during the constructor of a contract, + * as the code is not actually created until after the constructor finishes. + * @param _addr address to check + * @return whether the target address is a contract + */ + function isContract(address _addr) internal view returns (bool) { + uint256 size; + // XXX Currently there is no better way to check if there is a contract in an address + // than to check the size of the code at that address. + // See https://ethereum.stackexchange.com/a/14016/36603 + // for more details about how this works. + // TODO Check this again before the Serenity release, because all addresses will be + // contracts then. + // solium-disable-next-line security/no-inline-assembly + assembly { size := extcodesize(_addr) } + return size > 0; + } + +} \ No newline at end of file diff --git a/contracts/sponsorship/SponsorshipPaymaster.sol b/contracts/sponsorship/SponsorshipPaymaster.sol index c6a93bb..89b2c00 100644 --- a/contracts/sponsorship/SponsorshipPaymaster.sol +++ b/contracts/sponsorship/SponsorshipPaymaster.sol @@ -9,6 +9,7 @@ import {UserOperation, UserOperationLib} from "@account-abstraction/contracts/in import "../BasePaymaster.sol"; import {SponsorshipPaymasterErrors} from "../common/Errors.sol"; import {MathLib} from "../libs/MathLib.sol"; +import {AddressUtils} from "../libs/AddressUtils.sol"; import {ISponsorshipPaymaster} from "../interfaces/paymasters/ISponsorshipPaymaster.sol"; /** @@ -29,6 +30,7 @@ contract SponsorshipPaymaster is ISponsorshipPaymaster { using ECDSA for bytes32; + using AddressUtils for address; using UserOperationLib for UserOperation; uint32 private constant PRICE_DENOMINATOR = 1e6; @@ -72,11 +74,10 @@ contract SponsorshipPaymaster is * @param paymasterId dapp identifier for which deposit is being made */ function depositFor(address paymasterId) external payable nonReentrant { + if(paymasterId.isContract()) revert PaymasterIdCannotBeContract(); if (paymasterId == address(0)) revert PaymasterIdCannotBeZero(); if (msg.value == 0) revert DepositCanNotBeZero(); - paymasterIdBalances[paymasterId] = - paymasterIdBalances[paymasterId] + - msg.value; + paymasterIdBalances[paymasterId] += msg.value; entryPoint.depositTo{value: msg.value}(address(this)); emit GasDeposited(paymasterId, msg.value); } @@ -110,6 +111,7 @@ contract SponsorshipPaymaster is function setFeeCollector( address _newFeeCollector ) external payable onlyOwner { + if(_newFeeCollector.isContract()) revert FeeCollectorCannotBeContract(); if (_newFeeCollector == address(0)) revert FeeCollectorCannotBeZero(); address oldFeeCollector = feeCollector; assembly { @@ -324,7 +326,6 @@ contract SponsorshipPaymaster is require(priceMarkup <= 2e6, "Verifying PM:high markup %"); uint32 dynamicMarkup = MathLib.maxuint32(priceMarkup, fixedPriceMarkup); - require(dynamicMarkup >= 1e6, "Verifying PM:low markup %"); uint256 effectiveCost = (requiredPreFund * dynamicMarkup) / PRICE_DENOMINATOR;