diff --git a/contracts/base/BasePaymaster.sol b/contracts/base/BasePaymaster.sol index bc1042e..f3394c1 100644 --- a/contracts/base/BasePaymaster.sol +++ b/contracts/base/BasePaymaster.sol @@ -163,7 +163,10 @@ abstract contract BasePaymaster is IPaymaster, SoladyOwnable { require(msg.sender == address(entryPoint), "Sender not EntryPoint"); } - function isContract(address _addr) internal view returns (bool) { + /** + * Check if address is a contract + */ + function _isContract(address _addr) internal view returns (bool) { uint256 size; assembly ("memory-safe") { size := extcodesize(_addr) diff --git a/contracts/common/BiconomyTokenPaymasterErrors.sol b/contracts/common/BiconomyTokenPaymasterErrors.sol index 9293b21..1aa0cbd 100644 --- a/contracts/common/BiconomyTokenPaymasterErrors.sol +++ b/contracts/common/BiconomyTokenPaymasterErrors.sol @@ -2,5 +2,27 @@ pragma solidity ^0.8.26; contract BiconomyTokenPaymasterErrors { + /** + * @notice Throws when the verifiying signer address provided is address(0) + */ + error VerifyingSignerCanNotBeZero(); + /** + * @notice Throws when the fee collector address provided is address(0) + */ + error FeeCollectorCanNotBeZero(); + + /** + * @notice Throws when the fee collector address provided is a deployed contract + */ + error FeeCollectorCanNotBeContract(); + + /** + * @notice Throws when the fee collector address provided is a deployed contract + */ + error VerifyingSignerCanNotBeContract(); + /** + * @notice Throws when trying unaccountedGas is too high + */ + error UnaccountedGasTooHigh(); } diff --git a/contracts/interfaces/IBiconomySponsorshipPaymaster.sol b/contracts/interfaces/IBiconomySponsorshipPaymaster.sol index a2dcf17..7ad2651 100644 --- a/contracts/interfaces/IBiconomySponsorshipPaymaster.sol +++ b/contracts/interfaces/IBiconomySponsorshipPaymaster.sol @@ -22,7 +22,7 @@ interface IBiconomySponsorshipPaymaster{ function setFeeCollector(address _newFeeCollector) external payable; - function setUnaccountedGas(uint48 value) external payable; + function setUnaccountedGas(uint16 value) external payable; function withdrawERC20(IERC20 token, address target, uint256 amount) external; diff --git a/contracts/interfaces/IBiconomyTokenPaymaster.sol b/contracts/interfaces/IBiconomyTokenPaymaster.sol index 2347f38..59a7afa 100644 --- a/contracts/interfaces/IBiconomyTokenPaymaster.sol +++ b/contracts/interfaces/IBiconomyTokenPaymaster.sol @@ -2,5 +2,27 @@ pragma solidity ^0.8.26; interface IBiconomyTokenPaymaster { - -} \ No newline at end of file + enum ExchangeRateSource { + EXTERNAL_EXCHANGE_RATE, + ORACLE_BASED, + TWAP_BASED + } + + event UnaccountedGasChanged(uint256 indexed oldValue, uint256 indexed newValue); + event FixedDynamicAdjustmentChanged(uint32 indexed oldValue, uint32 indexed newValue); + event VerifyingSignerChanged(address indexed oldSigner, address indexed newSigner, address indexed actor); + event FeeCollectorChanged(address indexed oldFeeCollector, address indexed newFeeCollector, address indexed actor); + event GasDeposited(address indexed paymasterId, uint256 indexed value); + event GasWithdrawn(address indexed paymasterId, address indexed to, uint256 indexed value); + event GasBalanceDeducted(address indexed paymasterId, uint256 indexed charge, bytes32 indexed userOpHash); + event DynamicAdjustmentCollected(address indexed paymasterId, uint256 indexed dynamicAdjustment); + event Received(address indexed sender, uint256 value); + event TokensWithdrawn(address indexed token, address indexed to, uint256 indexed amount, address actor); + + + function setSigner(address _newVerifyingSigner) external payable; + + function setFeeCollector(address _newFeeCollector) external payable; + + function setUnaccountedGas(uint16 value) external payable; +} diff --git a/contracts/sponsorship/BiconomySponsorshipPaymaster.sol b/contracts/sponsorship/BiconomySponsorshipPaymaster.sol index 7faa2d7..9c4c9b8 100644 --- a/contracts/sponsorship/BiconomySponsorshipPaymaster.sol +++ b/contracts/sponsorship/BiconomySponsorshipPaymaster.sol @@ -40,14 +40,13 @@ contract BiconomySponsorshipPaymaster is address public verifyingSigner; address public feeCollector; - uint48 public unaccountedGas; + uint16 public unaccountedGas; uint32 private constant PRICE_DENOMINATOR = 1e6; - // note: could rename to PAYMASTER_ID_OFFSET + // Offset in PaymasterAndData to get to PAYMASTER_ID_OFFSET uint256 private constant PAYMASTER_ID_OFFSET = PAYMASTER_DATA_OFFSET; - // Limit for unaccounted gas cost - uint16 private constant UNACCOUNTED_GAS_LIMIT = 10_000; + uint16 private constant UNACCOUNTED_GAS_LIMIT = 50_000; mapping(address => uint256) public paymasterIdBalances; @@ -56,18 +55,14 @@ contract BiconomySponsorshipPaymaster is IEntryPoint _entryPoint, address _verifyingSigner, address _feeCollector, - uint48 _unaccountedGas + uint16 _unaccountedGas ) BasePaymaster(_owner, _entryPoint) { - if (_verifyingSigner == address(0)) { - revert VerifyingSignerCanNotBeZero(); - } else if (_feeCollector == address(0)) { - revert FeeCollectorCanNotBeZero(); - } else if (_unaccountedGas > UNACCOUNTED_GAS_LIMIT) { - revert UnaccountedGasTooHigh(); + _checkConstructorArgs(_verifyingSigner, _feeCollector, _unaccountedGas); + assembly ("memory-safe") { + sstore(verifyingSigner.slot, _verifyingSigner) } - verifyingSigner = _verifyingSigner; feeCollector = _feeCollector; unaccountedGas = _unaccountedGas; } @@ -97,7 +92,7 @@ contract BiconomySponsorshipPaymaster is * After setting the new signer address, it will emit an event VerifyingSignerChanged. */ function setSigner(address _newVerifyingSigner) external payable override onlyOwner { - if (isContract(_newVerifyingSigner)) revert VerifyingSignerCanNotBeContract(); + if (_isContract(_newVerifyingSigner)) revert VerifyingSignerCanNotBeContract(); if (_newVerifyingSigner == address(0)) { revert VerifyingSignerCanNotBeZero(); } @@ -116,6 +111,7 @@ contract BiconomySponsorshipPaymaster is * After setting the new fee collector address, it will emit an event FeeCollectorChanged. */ function setFeeCollector(address _newFeeCollector) external payable override onlyOwner { + if (_isContract(_newFeeCollector)) revert FeeCollectorCanNotBeContract(); if (_newFeeCollector == address(0)) revert FeeCollectorCanNotBeZero(); address oldFeeCollector = feeCollector; feeCollector = _newFeeCollector; @@ -127,11 +123,11 @@ contract BiconomySponsorshipPaymaster is * @param value The new value to be set as the unaccountedEPGasOverhead. * @notice only to be called by the owner of the contract. */ - function setUnaccountedGas(uint48 value) external payable override onlyOwner { + function setUnaccountedGas(uint16 value) external payable override onlyOwner { if (value > UNACCOUNTED_GAS_LIMIT) { revert UnaccountedGasTooHigh(); } - uint256 oldValue = unaccountedGas; + uint16 oldValue = unaccountedGas; unaccountedGas = value; emit UnaccountedGasChanged(oldValue, value); } @@ -139,7 +135,7 @@ contract BiconomySponsorshipPaymaster is /** * @dev Override the default implementation. */ - function deposit() external payable override virtual { + function deposit() external payable virtual override { revert UseDepositForInstead(); } @@ -346,4 +342,18 @@ contract BiconomySponsorshipPaymaster is SafeTransferLib.safeTransfer(address(token), target, amount); emit TokensWithdrawn(address(token), target, amount, msg.sender); } + + function _checkConstructorArgs(address _verifyingSigner, address _feeCollector, uint16 _unaccountedGas) internal view { + if (_verifyingSigner == address(0)) { + revert VerifyingSignerCanNotBeZero(); + } else if (_isContract(_verifyingSigner)) { + revert VerifyingSignerCanNotBeContract(); + } else if (_feeCollector == address(0)) { + revert FeeCollectorCanNotBeZero(); + } else if (_isContract(_feeCollector)) { + revert FeeCollectorCanNotBeContract(); + } else if (_unaccountedGas > UNACCOUNTED_GAS_LIMIT) { + revert UnaccountedGasTooHigh(); + } + } } diff --git a/contracts/token/BiconomyTokenPaymaster.sol b/contracts/token/BiconomyTokenPaymaster.sol index d8cd1d0..20263f4 100644 --- a/contracts/token/BiconomyTokenPaymaster.sol +++ b/contracts/token/BiconomyTokenPaymaster.sol @@ -10,6 +10,16 @@ import { BasePaymaster } from "../base/BasePaymaster.sol"; import { BiconomyTokenPaymasterErrors } from "../common/BiconomyTokenPaymasterErrors.sol"; import { IBiconomyTokenPaymaster } from "../interfaces/IBiconomyTokenPaymaster.sol"; +/** + * @title BiconomyTokenPaymaster + * @author ShivaanshK + * @author livingrockrises + * @notice Token Paymaster for v0.7 Entry Point + * @dev A paymaster that allows user to pay gas fee in ERC20 tokens. The paymaster owner chooses which tokens to + * accept. The payment manager (usually the owner) first deposits native gas into the EntryPoint. Then, for each + * transaction, it takes the gas fee from the user's ERC20 token balance. The exchange rate between ETH and the token is + * calculated using 1 of three methods: external price source, off-chain oracle, or a TWAP oracle. + */ contract BiconomyTokenPaymaster is BasePaymaster, ReentrancyGuard, @@ -19,12 +29,86 @@ contract BiconomyTokenPaymaster is using UserOperationLib for PackedUserOperation; using SignatureCheckerLib for address; + address public verifyingSigner; + address public feeCollector; + uint16 public unaccountedGas; + + // Limit for unaccounted gas cost + uint16 private constant UNACCOUNTED_GAS_LIMIT = 50_000; + constructor( address _owner, - IEntryPoint _entryPoint + IEntryPoint _entryPoint, + address _verifyingSigner, + address _feeCollector, + uint16 _unaccountedGas ) BasePaymaster(_owner, _entryPoint) - { } + { + _checkConstructorArgs(_verifyingSigner, _feeCollector, _unaccountedGas); + assembly ("memory-safe") { + sstore(verifyingSigner.slot, _verifyingSigner) + } + verifyingSigner = _verifyingSigner; + feeCollector = _feeCollector; + unaccountedGas = _unaccountedGas; + } + + /** + * @dev Set a new verifying signer address. + * Can only be called by the owner of the contract. + * @param _newVerifyingSigner The new address to be set as the verifying signer. + * @notice If _newVerifyingSigner is set to zero address, it will revert with an error. + * After setting the new signer address, it will emit an event VerifyingSignerChanged. + */ + function setSigner(address _newVerifyingSigner) external payable override onlyOwner { + if (_isContract(_newVerifyingSigner)) revert VerifyingSignerCanNotBeContract(); + if (_newVerifyingSigner == address(0)) { + revert VerifyingSignerCanNotBeZero(); + } + address oldSigner = verifyingSigner; + assembly ("memory-safe") { + sstore(verifyingSigner.slot, _newVerifyingSigner) + } + emit VerifyingSignerChanged(oldSigner, _newVerifyingSigner, msg.sender); + } + + /** + * @dev Set a new fee collector address. + * Can only be called by the owner of the contract. + * @param _newFeeCollector The new address to be set as the fee collector. + * @notice If _newFeeCollector is set to zero address, it will revert with an error. + * After setting the new fee collector address, it will emit an event FeeCollectorChanged. + */ + function setFeeCollector(address _newFeeCollector) external payable override onlyOwner { + if (_isContract(_newFeeCollector)) revert FeeCollectorCanNotBeContract(); + if (_newFeeCollector == address(0)) revert FeeCollectorCanNotBeZero(); + address oldFeeCollector = feeCollector; + feeCollector = _newFeeCollector; + emit FeeCollectorChanged(oldFeeCollector, _newFeeCollector, msg.sender); + } + + /** + * @dev Set a new unaccountedEPGasOverhead value. + * @param value The new value to be set as the unaccountedEPGasOverhead. + * @notice only to be called by the owner of the contract. + */ + function setUnaccountedGas(uint16 value) external payable override onlyOwner { + if (value > UNACCOUNTED_GAS_LIMIT) { + revert UnaccountedGasTooHigh(); + } + uint16 oldValue = unaccountedGas; + unaccountedGas = value; + emit UnaccountedGasChanged(oldValue, value); + } + + /** + * Add a deposit in native currency for this paymaster, used for paying for transaction fees. + * This is ideally done by the entity who is managing the received ERC20 gas tokens. + */ + function deposit() public payable virtual override nonReentrant { + entryPoint.depositTo{ value: msg.value }(address(this)); + } /** * @dev Validate a user operation. @@ -64,4 +148,25 @@ contract BiconomyTokenPaymaster is { // Implementation of post-operation logic } + + function _checkConstructorArgs( + address _verifyingSigner, + address _feeCollector, + uint16 _unaccountedGas + ) + internal + view + { + if (_verifyingSigner == address(0)) { + revert VerifyingSignerCanNotBeZero(); + } else if (_isContract(_verifyingSigner)) { + revert VerifyingSignerCanNotBeContract(); + } else if (_feeCollector == address(0)) { + revert FeeCollectorCanNotBeZero(); + } else if (_isContract(_feeCollector)) { + revert FeeCollectorCanNotBeContract(); + } else if (_unaccountedGas > UNACCOUNTED_GAS_LIMIT) { + revert UnaccountedGasTooHigh(); + } + } } diff --git a/test/base/BaseEventsAndErrors.sol b/test/base/BaseEventsAndErrors.sol index 187a880..021e399 100644 --- a/test/base/BaseEventsAndErrors.sol +++ b/test/base/BaseEventsAndErrors.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Unlicensed pragma solidity ^0.8.26; -import { EventsAndErrors } from "nexus/test/foundry/utils/EventsAndErrors.sol"; -import { BiconomySponsorshipPaymasterErrors } from "./../../../contracts/common/BiconomySponsorshipPaymasterErrors.sol"; +import { EventsAndErrors } from "@nexus/test/foundry/utils/EventsAndErrors.sol"; +import { BiconomySponsorshipPaymasterErrors } from "../../contracts/common/BiconomySponsorshipPaymasterErrors.sol"; contract BaseEventsAndErrors is EventsAndErrors, BiconomySponsorshipPaymasterErrors { // ========================== diff --git a/test/base/TestBase.sol b/test/base/TestBase.sol index 427bfe8..cd8c222 100644 --- a/test/base/TestBase.sol +++ b/test/base/TestBase.sol @@ -4,25 +4,25 @@ pragma solidity ^0.8.26; import { Test } from "forge-std/src/Test.sol"; import { Vm } from "forge-std/src/Vm.sol"; -import "solady/src/utils/ECDSA.sol"; - -import { EntryPoint } from "account-abstraction/contracts/core/EntryPoint.sol"; -import { IEntryPoint } from "account-abstraction/contracts/interfaces/IEntryPoint.sol"; -import { IAccount } from "account-abstraction/contracts/interfaces/IAccount.sol"; -import { Exec } from "account-abstraction/contracts/utils/Exec.sol"; -import { IPaymaster } from "account-abstraction/contracts/interfaces/IPaymaster.sol"; -import { PackedUserOperation } from "account-abstraction/contracts/interfaces/PackedUserOperation.sol"; - -import { Nexus } from "nexus/contracts/Nexus.sol"; -import { NexusAccountFactory } from "nexus/contracts/factory/NexusAccountFactory.sol"; -import { BiconomyMetaFactory } from "nexus/contracts/factory/BiconomyMetaFactory.sol"; -import { MockValidator } from "nexus/contracts/mocks/MockValidator.sol"; -import { BootstrapLib } from "nexus/contracts/lib/BootstrapLib.sol"; -import { Bootstrap, BootstrapConfig } from "nexus/contracts/utils/Bootstrap.sol"; -import { CheatCodes } from "nexus/test/foundry/utils/CheatCodes.sol"; +import "@solady/src/utils/ECDSA.sol"; + +import { EntryPoint } from "@account-abstraction/contracts/core/EntryPoint.sol"; +import { IEntryPoint } from "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; +import { IAccount } from "@account-abstraction/contracts/interfaces/IAccount.sol"; +import { Exec } from "@account-abstraction/contracts/utils/Exec.sol"; +import { IPaymaster } from "@account-abstraction/contracts/interfaces/IPaymaster.sol"; +import { PackedUserOperation } from "@account-abstraction/contracts/interfaces/PackedUserOperation.sol"; + +import { Nexus } from "@nexus/contracts/Nexus.sol"; +import { NexusAccountFactory } from "@nexus/contracts/factory/NexusAccountFactory.sol"; +import { BiconomyMetaFactory } from "@nexus/contracts/factory/BiconomyMetaFactory.sol"; +import { MockValidator } from "@nexus/contracts/mocks/MockValidator.sol"; +import { BootstrapLib } from "@nexus/contracts/lib/BootstrapLib.sol"; +import { Bootstrap, BootstrapConfig } from "@nexus/contracts/utils/Bootstrap.sol"; +import { CheatCodes } from "@nexus/test/foundry/utils/CheatCodes.sol"; import { BaseEventsAndErrors } from "./BaseEventsAndErrors.sol"; -import { BiconomySponsorshipPaymaster } from "../../../contracts/sponsorship/BiconomySponsorshipPaymaster.sol"; +import { BiconomySponsorshipPaymaster } from "../../contracts/sponsorship/BiconomySponsorshipPaymaster.sol"; abstract contract TestBase is CheatCodes, BaseEventsAndErrors { // ----------------------------------------- @@ -409,7 +409,7 @@ abstract contract TestBase is CheatCodes, BaseEventsAndErrors { vm.startPrank(paymaster.owner()); // Set unaccounted gas to be gas used in postop + 1000 for EP overhead and penalty - paymaster.setUnaccountedGas(uint48(postopGasUsed + 1000)); + paymaster.setUnaccountedGas(uint16(postopGasUsed + 1000)); vm.stopPrank(); // Ammend the userop to have new gas limits and signature diff --git a/test/unit/concrete/TestSponsorshipPaymasterWithDynamicAdjustmentTest.t.sol b/test/unit/concrete/TestSponsorshipPaymaster.t.sol similarity index 93% rename from test/unit/concrete/TestSponsorshipPaymasterWithDynamicAdjustmentTest.t.sol rename to test/unit/concrete/TestSponsorshipPaymaster.t.sol index 05b9362..3457c50 100644 --- a/test/unit/concrete/TestSponsorshipPaymasterWithDynamicAdjustmentTest.t.sol +++ b/test/unit/concrete/TestSponsorshipPaymaster.t.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.26; import { TestBase } from "../../base/TestBase.sol"; -import { IBiconomySponsorshipPaymaster } from "../../../../contracts/interfaces/IBiconomySponsorshipPaymaster.sol"; -import { BiconomySponsorshipPaymaster } from "../../../../contracts/sponsorship/BiconomySponsorshipPaymaster.sol"; -import { PackedUserOperation } from "account-abstraction/contracts/core/UserOperationLib.sol"; -import { MockToken } from "./../../../../lib/nexus/contracts/mocks/MockToken.sol"; +import { IBiconomySponsorshipPaymaster } from "../../../contracts/interfaces/IBiconomySponsorshipPaymaster.sol"; +import { BiconomySponsorshipPaymaster } from "../../../contracts/sponsorship/BiconomySponsorshipPaymaster.sol"; +import { PackedUserOperation } from "@account-abstraction/contracts/core/UserOperationLib.sol"; +import { MockToken } from "@nexus/contracts/mocks/MockToken.sol"; contract TestSponsorshipPaymasterWithDynamicAdjustment is TestBase { BiconomySponsorshipPaymaster public bicoPaymaster; @@ -36,15 +36,28 @@ contract TestSponsorshipPaymasterWithDynamicAdjustment is TestBase { ); } + function test_RevertIf_DeployWithSignerAsContract() external { + vm.expectRevert(abi.encodeWithSelector(VerifyingSignerCanNotBeContract.selector)); + new BiconomySponsorshipPaymaster( + PAYMASTER_OWNER.addr, ENTRYPOINT, address(ENTRYPOINT), PAYMASTER_FEE_COLLECTOR.addr, 7e3 + ); + } + + function test_RevertIf_DeployWithFeeCollectorSetToZero() external { vm.expectRevert(abi.encodeWithSelector(FeeCollectorCanNotBeZero.selector)); new BiconomySponsorshipPaymaster(PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, address(0), 7e3); } + function test_RevertIf_DeployWithFeeCollectorAsContract() external { + vm.expectRevert(abi.encodeWithSelector(FeeCollectorCanNotBeContract.selector)); + new BiconomySponsorshipPaymaster(PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, address(ENTRYPOINT), 7e3); + } + function test_RevertIf_DeployWithUnaccountedGasCostTooHigh() external { vm.expectRevert(abi.encodeWithSelector(UnaccountedGasTooHigh.selector)); new BiconomySponsorshipPaymaster( - PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, PAYMASTER_FEE_COLLECTOR.addr, 10_001 + PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, PAYMASTER_FEE_COLLECTOR.addr, 50_001 ); } @@ -117,8 +130,8 @@ contract TestSponsorshipPaymasterWithDynamicAdjustment is TestBase { } function test_SetUnaccountedGas() external prankModifier(PAYMASTER_OWNER.addr) { - uint48 initialUnaccountedGas = bicoPaymaster.unaccountedGas(); - uint48 newUnaccountedGas = 5000; + uint16 initialUnaccountedGas = bicoPaymaster.unaccountedGas(); + uint16 newUnaccountedGas = 5000; vm.expectEmit(true, true, false, true, address(bicoPaymaster)); emit IBiconomySponsorshipPaymaster.UnaccountedGasChanged(initialUnaccountedGas, newUnaccountedGas); @@ -129,7 +142,7 @@ contract TestSponsorshipPaymasterWithDynamicAdjustment is TestBase { } function test_RevertIf_SetUnaccountedGasToHigh() external prankModifier(PAYMASTER_OWNER.addr) { - uint48 newUnaccountedGas = 10_001; + uint16 newUnaccountedGas = 50_001; vm.expectRevert(abi.encodeWithSelector(UnaccountedGasTooHigh.selector)); bicoPaymaster.setUnaccountedGas(newUnaccountedGas); } diff --git a/test/unit/fuzz/TestFuzz_TestSponsorshipPaymasterWithPremium.t.sol b/test/unit/fuzz/TestFuzz_TestSponsorshipPaymaster.t.sol similarity index 94% rename from test/unit/fuzz/TestFuzz_TestSponsorshipPaymasterWithPremium.t.sol rename to test/unit/fuzz/TestFuzz_TestSponsorshipPaymaster.t.sol index bac7265..1cf605a 100644 --- a/test/unit/fuzz/TestFuzz_TestSponsorshipPaymasterWithPremium.t.sol +++ b/test/unit/fuzz/TestFuzz_TestSponsorshipPaymaster.t.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.26; import { TestBase } from "../../base/TestBase.sol"; -import { IBiconomySponsorshipPaymaster } from "../../../../contracts/interfaces/IBiconomySponsorshipPaymaster.sol"; -import { BiconomySponsorshipPaymaster } from "../../../../contracts/sponsorship/BiconomySponsorshipPaymaster.sol"; -import { MockToken } from "./../../../../lib/nexus/contracts/mocks/MockToken.sol"; -import { PackedUserOperation } from "account-abstraction/contracts/interfaces/PackedUserOperation.sol"; +import { IBiconomySponsorshipPaymaster } from "../../../contracts/interfaces/IBiconomySponsorshipPaymaster.sol"; +import { BiconomySponsorshipPaymaster } from "../../../contracts/sponsorship/BiconomySponsorshipPaymaster.sol"; +import { MockToken } from "@nexus/contracts/mocks/MockToken.sol"; +import { PackedUserOperation } from "@account-abstraction/contracts/interfaces/PackedUserOperation.sol"; contract TestFuzz_SponsorshipPaymasterWithDynamicAdjustment is TestBase { BiconomySponsorshipPaymaster public bicoPaymaster;