From 5ad56198927d055efb57675415511c85e4d61104 Mon Sep 17 00:00:00 2001 From: Shivaansh Kapoor Date: Mon, 8 Jul 2024 11:46:24 +0400 Subject: [PATCH] make tests more modular --- .../SponsorshipPaymasterWithPremium.sol | 22 ++-- test/foundry/base/NexusTestBase.sol | 62 +++++++++++ ...tSponsorshipPaymasterWithPremiumTest.t.sol | 102 ++++-------------- ..._TestSponsorshipPaymasterWithPremium.t.sol | 49 ++------- 4 files changed, 101 insertions(+), 134 deletions(-) diff --git a/contracts/sponsorship/SponsorshipPaymasterWithPremium.sol b/contracts/sponsorship/SponsorshipPaymasterWithPremium.sol index 5b06711..e63b539 100644 --- a/contracts/sponsorship/SponsorshipPaymasterWithPremium.sol +++ b/contracts/sponsorship/SponsorshipPaymasterWithPremium.sol @@ -234,23 +234,23 @@ contract BiconomySponsorshipPaymaster is /// @param actualGasCost The actual gas cost of the transaction. function _postOp(PostOpMode, bytes calldata context, uint256 actualGasCost, uint256) internal override { unchecked { - (address paymasterId, uint32 dynamicMarkup, bytes32 userOpHash) = + (address paymasterId, uint32 dynamicAdjustment, bytes32 userOpHash) = abi.decode(context, (address, uint32, bytes32)); - uint256 costIncludingPremium = (actualGasCost * dynamicMarkup) / PRICE_DENOMINATOR; + uint256 adjustedGasCost = (actualGasCost * dynamicAdjustment) / PRICE_DENOMINATOR; - // deduct with premium - paymasterIdBalances[paymasterId] -= costIncludingPremium; + // Deduct the adjusted cost + paymasterIdBalances[paymasterId] -= adjustedGasCost; - if (costIncludingPremium > actualGasCost) { - // "collect" premium - uint256 actualPremium = costIncludingPremium - actualGasCost; - paymasterIdBalances[feeCollector] += actualPremium; - // Review if we should emit balToDeduct as well - emit PremiumCollected(paymasterId, actualPremium); + if (adjustedGasCost > actualGasCost) { + // Add premium to fee + uint256 premium = adjustedGasCost - actualGasCost; + paymasterIdBalances[feeCollector] += premium; + // Review if we should emit adjustedGasCost as well + emit PremiumCollected(paymasterId, premium); } - emit GasBalanceDeducted(paymasterId, costIncludingPremium, userOpHash); + emit GasBalanceDeducted(paymasterId, adjustedGasCost, userOpHash); } } diff --git a/test/foundry/base/NexusTestBase.sol b/test/foundry/base/NexusTestBase.sol index cd7dbaf..dbe176c 100644 --- a/test/foundry/base/NexusTestBase.sol +++ b/test/foundry/base/NexusTestBase.sol @@ -351,6 +351,46 @@ abstract contract NexusTestBase is CheatCodes, BaseEventsAndErrors { postopGasLimit = postopGasLimit - gasleft(); } + function createUserOp( + Vm.Wallet memory sender, + BiconomySponsorshipPaymaster paymaster, + uint32 premium + ) + internal + returns (PackedUserOperation memory userOp, bytes32 userOpHash) + { + // Create userOp with no paymaster gas estimates + uint48 validUntil = uint48(block.timestamp + 1 days); + uint48 validAfter = uint48(block.timestamp); + + userOp = buildUserOpWithCalldata(sender, "", address(VALIDATOR_MODULE)); + + userOp.paymasterAndData = generateAndSignPaymasterData( + userOp, PAYMASTER_SIGNER, paymaster, 3e6, 3e6, DAPP_ACCOUNT.addr, validUntil, validAfter, premium + ); + userOp.signature = signUserOp(sender, userOp); + + // Estimate paymaster gas limits + userOpHash = ENTRYPOINT.getUserOpHash(userOp); + (uint256 validationGasLimit, uint256 postopGasLimit) = + estimatePaymasterGasCosts(paymaster, userOp, userOpHash, 5e4); + + // Ammend the userop to have new gas limits and signature + userOp.paymasterAndData = generateAndSignPaymasterData( + userOp, + PAYMASTER_SIGNER, + paymaster, + uint128(validationGasLimit), + uint128(postopGasLimit), + DAPP_ACCOUNT.addr, + validUntil, + validAfter, + premium + ); + userOp.signature = signUserOp(sender, userOp); + userOpHash = ENTRYPOINT.getUserOpHash(userOp); + } + /// @notice Generates and signs the paymaster data for a user operation. /// @dev This function prepares the `paymasterAndData` field for a `PackedUserOperation` with the correct signature. /// @param userOp The user operation to be signed. @@ -417,4 +457,26 @@ abstract contract NexusTestBase is CheatCodes, BaseEventsAndErrors { } return result; } + + function getPremiums( + BiconomySponsorshipPaymaster paymaster, + uint256 initialDappPaymasterBalance, + uint256 initialFeeCollectorBalance, + uint32 premium + ) + internal + view + returns (uint256 expectedPremium, uint256 actualPremium) + { + uint256 resultingDappPaymasterBalance = paymaster.getBalance(DAPP_ACCOUNT.addr); + uint256 resultingFeeCollectorPaymasterBalance = paymaster.getBalance(PAYMASTER_FEE_COLLECTOR.addr); + + uint256 totalGasFeesCharged = initialDappPaymasterBalance - resultingDappPaymasterBalance; + + if (premium >= 1e6) { + //premium + expectedPremium = totalGasFeesCharged - ((totalGasFeesCharged * 1e6) / premium); + actualPremium = resultingFeeCollectorPaymasterBalance - initialFeeCollectorBalance; + } else revert("Premium must be more than 1e6"); + } } diff --git a/test/foundry/unit/concrete/TestSponsorshipPaymasterWithPremiumTest.t.sol b/test/foundry/unit/concrete/TestSponsorshipPaymasterWithPremiumTest.t.sol index 0f6ed46..a1df8d2 100644 --- a/test/foundry/unit/concrete/TestSponsorshipPaymasterWithPremiumTest.t.sol +++ b/test/foundry/unit/concrete/TestSponsorshipPaymasterWithPremiumTest.t.sol @@ -134,94 +134,40 @@ contract TestSponsorshipPaymasterWithPremium is NexusTestBase { bicoPaymaster.deposit{ value: 1 ether }(); } - function test_WithdrawTo() external prankModifier(DAPP_ACCOUNT.addr) { - uint256 initialDappPaymasterBalance = 10 ether; - bicoPaymaster.depositFor{ value: initialDappPaymasterBalance }(DAPP_ACCOUNT.addr); - - PackedUserOperation[] memory ops = new PackedUserOperation[](1); - - uint48 validUntil = uint48(block.timestamp + 1 days); - uint48 validAfter = uint48(block.timestamp); - - PackedUserOperation memory userOp = buildUserOpWithCalldata(ALICE, "", address(VALIDATOR_MODULE)); - - // No premium + function test_ValidatePaymasterAndPostOpWithoutPremium() external prankModifier(DAPP_ACCOUNT.addr) { + bicoPaymaster.depositFor{ value: 10 ether }(DAPP_ACCOUNT.addr); + // No premoium uint32 premium = 1e6; - userOp.paymasterAndData = generateAndSignPaymasterData( - userOp, PAYMASTER_SIGNER, bicoPaymaster, 3e6, 3e6, DAPP_ACCOUNT.addr, validUntil, validAfter, premium - ); - userOp.signature = signUserOp(ALICE, userOp); - - // Estimate paymaster gas limits - bytes32 userOpHash = ENTRYPOINT.getUserOpHash(userOp); - (uint256 validationGasLimit, uint256 postopGasLimit) = - estimatePaymasterGasCosts(bicoPaymaster, userOp, userOpHash, 5e4); - // Ammend the userop to have new gas limits and signature - userOp.paymasterAndData = generateAndSignPaymasterData( - userOp, - PAYMASTER_SIGNER, - bicoPaymaster, - uint128(validationGasLimit), - uint128(postopGasLimit), - DAPP_ACCOUNT.addr, - validUntil, - validAfter, - premium - ); - userOp.signature = signUserOp(ALICE, userOp); + PackedUserOperation[] memory ops = new PackedUserOperation[](1); + (PackedUserOperation memory userOp, bytes32 userOpHash) = createUserOp(ALICE, bicoPaymaster, premium); ops[0] = userOp; - userOpHash = ENTRYPOINT.getUserOpHash(userOp); + + uint256 initialDappPaymasterBalance = bicoPaymaster.getBalance(DAPP_ACCOUNT.addr); + uint256 initialFeeCollectorBalance = bicoPaymaster.getBalance(PAYMASTER_FEE_COLLECTOR.addr); vm.expectEmit(true, false, true, true, address(bicoPaymaster)); emit IBiconomySponsorshipPaymaster.GasBalanceDeducted(DAPP_ACCOUNT.addr, 0, userOpHash); ENTRYPOINT.handleOps(ops, payable(BUNDLER.addr)); - uint256 resultingDappPaymasterBalance = bicoPaymaster.getBalance(DAPP_ACCOUNT.addr); - assertNotEq(initialDappPaymasterBalance, resultingDappPaymasterBalance); + (uint256 expectedPremium, uint256 actualPremium) = + getPremiums(bicoPaymaster, initialDappPaymasterBalance, initialFeeCollectorBalance, premium); + + assertEq(expectedPremium, actualPremium); } function test_ValidatePaymasterAndPostOpWithPremium() external { - uint256 initialDappPaymasterBalance = 10 ether; - bicoPaymaster.depositFor{ value: initialDappPaymasterBalance }(DAPP_ACCOUNT.addr); - - PackedUserOperation[] memory ops = new PackedUserOperation[](1); - - uint48 validUntil = uint48(block.timestamp + 1 days); - uint48 validAfter = uint48(block.timestamp); - - PackedUserOperation memory userOp = buildUserOpWithCalldata(ALICE, "", address(VALIDATOR_MODULE)); - - // Charge a 10% premium + bicoPaymaster.depositFor{ value: 10 ether }(DAPP_ACCOUNT.addr); + // 10% premium on gas cost uint32 premium = 1e6 + 1e5; - userOp.paymasterAndData = generateAndSignPaymasterData( - userOp, PAYMASTER_SIGNER, bicoPaymaster, 3e6, 3e6, DAPP_ACCOUNT.addr, validUntil, validAfter, premium - ); - userOp.signature = signUserOp(ALICE, userOp); - - // Estimate paymaster gas limits - bytes32 userOpHash = ENTRYPOINT.getUserOpHash(userOp); - (uint256 validationGasLimit, uint256 postopGasLimit) = - estimatePaymasterGasCosts(bicoPaymaster, userOp, userOpHash, 5e4); - // Ammend the userop to have new gas limits and signature - userOp.paymasterAndData = generateAndSignPaymasterData( - userOp, - PAYMASTER_SIGNER, - bicoPaymaster, - uint128(validationGasLimit), - uint128(postopGasLimit), - DAPP_ACCOUNT.addr, - validUntil, - validAfter, - premium - ); - userOp.signature = signUserOp(ALICE, userOp); + PackedUserOperation[] memory ops = new PackedUserOperation[](1); + (PackedUserOperation memory userOp, bytes32 userOpHash) = createUserOp(ALICE, bicoPaymaster, premium); ops[0] = userOp; - userOpHash = ENTRYPOINT.getUserOpHash(userOp); + uint256 initialDappPaymasterBalance = bicoPaymaster.getBalance(DAPP_ACCOUNT.addr); uint256 initialFeeCollectorBalance = bicoPaymaster.getBalance(PAYMASTER_FEE_COLLECTOR.addr); - initialDappPaymasterBalance = bicoPaymaster.getBalance(DAPP_ACCOUNT.addr); + // submit userops vm.expectEmit(true, false, false, true, address(bicoPaymaster)); emit IBiconomySponsorshipPaymaster.PremiumCollected(DAPP_ACCOUNT.addr, 0); @@ -229,16 +175,10 @@ contract TestSponsorshipPaymasterWithPremium is NexusTestBase { emit IBiconomySponsorshipPaymaster.GasBalanceDeducted(DAPP_ACCOUNT.addr, 0, userOpHash); ENTRYPOINT.handleOps(ops, payable(BUNDLER.addr)); - uint256 resultingDappPaymasterBalance = bicoPaymaster.getBalance(DAPP_ACCOUNT.addr); - uint256 resultingFeeCollectorPaymasterBalance = bicoPaymaster.getBalance(PAYMASTER_FEE_COLLECTOR.addr); - - uint256 totalGasFeesCharged = initialDappPaymasterBalance - resultingDappPaymasterBalance; - uint256 premiumCollected = resultingFeeCollectorPaymasterBalance - initialFeeCollectorBalance; - - uint256 expectedGasPayment = totalGasFeesCharged - premiumCollected; - uint256 expectedPremium = expectedGasPayment / 10; + (uint256 expectedPremium, uint256 actualPremium) = + getPremiums(bicoPaymaster, initialDappPaymasterBalance, initialFeeCollectorBalance, premium); - assertEq(premiumCollected, expectedPremium); + assertEq(expectedPremium, actualPremium); } function test_RevertIf_ValidatePaymasterUserOpWithIncorrectSignatureLength() external { diff --git a/test/foundry/unit/fuzz/TestFuzz_TestSponsorshipPaymasterWithPremium.t.sol b/test/foundry/unit/fuzz/TestFuzz_TestSponsorshipPaymasterWithPremium.t.sol index 25fe3d1..11b43e4 100644 --- a/test/foundry/unit/fuzz/TestFuzz_TestSponsorshipPaymasterWithPremium.t.sol +++ b/test/foundry/unit/fuzz/TestFuzz_TestSponsorshipPaymasterWithPremium.t.sol @@ -101,59 +101,24 @@ contract TestFuzz_SponsorshipPaymasterWithPremium is NexusTestBase { function testFuzz_ValidatePaymasterAndPostOpWithPremium(uint32 premium) external { vm.assume(premium <= 2e6); vm.assume(premium > 1e6); - - uint256 initialDappPaymasterBalance = 10 ether; - bicoPaymaster.depositFor{ value: initialDappPaymasterBalance }(DAPP_ACCOUNT.addr); + bicoPaymaster.depositFor{ value: 10 ether }(DAPP_ACCOUNT.addr); PackedUserOperation[] memory ops = new PackedUserOperation[](1); - - uint48 validUntil = uint48(block.timestamp + 1 days); - uint48 validAfter = uint48(block.timestamp); - - PackedUserOperation memory userOp = buildUserOpWithCalldata(ALICE, "", address(VALIDATOR_MODULE)); - - userOp.paymasterAndData = generateAndSignPaymasterData( - userOp, PAYMASTER_SIGNER, bicoPaymaster, 3e6, 3e6, DAPP_ACCOUNT.addr, validUntil, validAfter, premium - ); - userOp.signature = signUserOp(ALICE, userOp); - - // Estimate paymaster gas limits - bytes32 userOpHash = ENTRYPOINT.getUserOpHash(userOp); - (uint256 validationGasLimit, uint256 postopGasLimit) = - estimatePaymasterGasCosts(bicoPaymaster, userOp, userOpHash, 5e4); - - // Ammend the userop to have new gas limits and signature - userOp.paymasterAndData = generateAndSignPaymasterData( - userOp, - PAYMASTER_SIGNER, - bicoPaymaster, - uint128(validationGasLimit), - uint128(postopGasLimit), - DAPP_ACCOUNT.addr, - validUntil, - validAfter, - premium - ); - userOp.signature = signUserOp(ALICE, userOp); + (PackedUserOperation memory userOp, bytes32 userOpHash) = createUserOp(ALICE, bicoPaymaster, premium); ops[0] = userOp; - userOpHash = ENTRYPOINT.getUserOpHash(userOp); uint256 initialFeeCollectorBalance = bicoPaymaster.getBalance(PAYMASTER_FEE_COLLECTOR.addr); - initialDappPaymasterBalance = bicoPaymaster.getBalance(DAPP_ACCOUNT.addr); + uint256 initialDappPaymasterBalance = bicoPaymaster.getBalance(DAPP_ACCOUNT.addr); vm.expectEmit(true, false, false, true, address(bicoPaymaster)); emit IBiconomySponsorshipPaymaster.PremiumCollected(DAPP_ACCOUNT.addr, 0); vm.expectEmit(true, false, true, true, address(bicoPaymaster)); emit IBiconomySponsorshipPaymaster.GasBalanceDeducted(DAPP_ACCOUNT.addr, 0, userOpHash); ENTRYPOINT.handleOps(ops, payable(BUNDLER.addr)); - uint256 resultingDappPaymasterBalance = bicoPaymaster.getBalance(DAPP_ACCOUNT.addr); - uint256 resultingFeeCollectorPaymasterBalance = bicoPaymaster.getBalance(PAYMASTER_FEE_COLLECTOR.addr); - - uint256 totalGasFeesCharged = initialDappPaymasterBalance - resultingDappPaymasterBalance; + (uint256 expectedPremium, uint256 actualPremium) = + getPremiums(bicoPaymaster, initialDappPaymasterBalance, initialFeeCollectorBalance, premium); - uint256 premiumCollected = resultingFeeCollectorPaymasterBalance - initialFeeCollectorBalance; - uint256 expectedPremium = totalGasFeesCharged - ((totalGasFeesCharged * 1e6) / premium); - - assertEq(premiumCollected, expectedPremium); + assertEq(expectedPremium, actualPremium); } + }