diff --git a/foundry.toml b/foundry.toml index f84c8e9..6c13cf9 100644 --- a/foundry.toml +++ b/foundry.toml @@ -7,7 +7,7 @@ evm_version = "cancun" # See https://www.evmdiff.com/features?name=PUSH0&kind=opcode gas_reports = ["*"] optimizer = true - optimizer_runs = 800 + optimizer_runs = 10_000 out = "out" script = "scripts" solc = "0.8.27" diff --git a/package.json b/package.json index 041e4c6..5d2e3d8 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "url": "https://github.com/bcnmy" }, "dependencies": { - "@biconomy-devx/erc7579-msa": "^0.0.4", "@uniswap/v3-core": "https://github.com/Uniswap/v3-core#0.8", "@uniswap/v3-periphery": "https://github.com/Uniswap/v3-periphery#0.8", "accountabstraction": "https://github.com/eth-infinitism/account-abstraction#develop", diff --git a/test/base/TestBase.sol b/test/base/TestBase.sol index f4321cc..bfe07ee 100644 --- a/test/base/TestBase.sol +++ b/test/base/TestBase.sol @@ -37,6 +37,15 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { Vm.Wallet internal PAYMASTER_FEE_COLLECTOR; Vm.Wallet internal DAPP_ACCOUNT; + struct PaymasterData { + uint128 validationGasLimit; + uint128 postOpGasLimit; + address paymasterId; + uint48 validUntil; + uint48 validAfter; + uint32 priceMarkup; + } + // Used to buffer user op gas limits // GAS_LIMIT = (ESTIMATED_GAS * GAS_BUFFER_RATIO) / 100 uint8 private constant GAS_BUFFER_RATIO = 110; @@ -71,23 +80,25 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { } function estimateUserOpGasCosts(PackedUserOperation memory userOp) - internal - prankModifier(ENTRYPOINT_ADDRESS) - returns (uint256 verificationGasUsed, uint256 callGasUsed, uint256 verificationGasLimit, uint256 callGasLimit) - { - bytes32 userOpHash = ENTRYPOINT.getUserOpHash(userOp); - verificationGasUsed = gasleft(); - IAccount(userOp.sender).validateUserOp(userOp, userOpHash, 0); - verificationGasUsed = verificationGasUsed - gasleft(); - - callGasUsed = gasleft(); - bool success = Exec.call(userOp.sender, 0, userOp.callData, 3e6); - callGasUsed = callGasUsed - gasleft(); - assert(success); - - verificationGasLimit = (verificationGasUsed * GAS_BUFFER_RATIO) / 100; - callGasLimit = (callGasUsed * GAS_BUFFER_RATIO) / 100; - } + internal + prankModifier(ENTRYPOINT_ADDRESS) + returns (uint256 verificationGasUsed, uint256 callGasUsed, uint256 verificationGasLimit, uint256 callGasLimit) +{ + bytes32 userOpHash = ENTRYPOINT.getUserOpHash(userOp); + + // Use memory to store intermediate gas values + uint256 remainingGas = gasleft(); + IAccount(userOp.sender).validateUserOp(userOp, userOpHash, 0); + verificationGasUsed = remainingGas - gasleft(); + + remainingGas = gasleft(); + bool success = Exec.call(userOp.sender, 0, userOp.callData, 3e6); + callGasUsed = remainingGas - gasleft(); + assert(success); + + verificationGasLimit = (verificationGasUsed * GAS_BUFFER_RATIO) / 100; + callGasLimit = (callGasUsed * GAS_BUFFER_RATIO) / 100; +} function estimatePaymasterGasCosts( BiconomySponsorshipPaymaster paymaster, @@ -118,6 +129,7 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { function createUserOp( Vm.Wallet memory sender, + bytes memory callData, BiconomySponsorshipPaymaster paymaster, uint32 priceMarkup ) @@ -128,10 +140,12 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { uint48 validUntil = uint48(block.timestamp + 1 days); uint48 validAfter = uint48(block.timestamp); - userOp = buildUserOpWithCalldata(sender, "", address(VALIDATOR_MODULE)); + userOp = buildUserOpWithCalldata(sender, callData, address(VALIDATOR_MODULE)); + + PaymasterData memory pmData = PaymasterData(24000, uint128(35000), DAPP_ACCOUNT.addr, validUntil, validAfter, priceMarkup); (userOp.paymasterAndData,) = generateAndSignPaymasterData( - userOp, PAYMASTER_SIGNER, paymaster, 3e6, 8e3, DAPP_ACCOUNT.addr, validUntil, validAfter, priceMarkup + userOp, PAYMASTER_SIGNER, paymaster, pmData ); userOp.signature = signUserOp(sender, userOp); @@ -139,34 +153,25 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { // Estimate paymaster gas limits (, uint256 postopGasUsed, uint256 validationGasLimit, uint256 postopGasLimit) = estimatePaymasterGasCosts(paymaster, userOp, 5e4); - - // console2.log("postOpGasUsed"); - // console2.logUint(postopGasUsed); - - // uint256 prevValUnaccountedGas = paymaster.unaccountedGas(); - // console2.logUint(prevValUnaccountedGas); - - // Below may not be needed if unaccountedGas is set correctly - vm.startPrank(paymaster.owner()); - // Set unaccounted gas to be gas used in postop + 1000 for EP overhead and penalty - paymaster.setUnaccountedGas(postopGasUsed + 500); - vm.stopPrank(); - - // uint256 currentValUnaccountedGas = paymaster.unaccountedGas(); - // console2.logUint(currentValUnaccountedGas); - - // Ammend the userop to have new gas limits and signature - userOp.accountGasLimits = bytes32(abi.encodePacked(uint128(verificationGasLimit), uint128(callGasLimit))); + console2.log("verificationGasLimit"); + console2.logUint(verificationGasLimit); + console2.log("callGasLimit"); + console2.logUint(callGasLimit); + console2.log("validationGasLimit"); + console2.logUint(validationGasLimit); + console2.log("postopGasLimit"); + console2.logUint(postopGasLimit); + console2.log("postopGasUsed"); + console2.logUint(postopGasUsed); + + + userOp.accountGasLimits = bytes32(abi.encodePacked(uint128(55000), uint128(0))); + PaymasterData memory pmDataNew = PaymasterData(uint128(24000), uint128(35000), DAPP_ACCOUNT.addr, validUntil, validAfter, priceMarkup); (userOp.paymasterAndData,) = generateAndSignPaymasterData( userOp, PAYMASTER_SIGNER, paymaster, - uint128(validationGasLimit), - uint128(postopGasLimit), - DAPP_ACCOUNT.addr, - validUntil, - validAfter, - priceMarkup + pmDataNew ); userOp.signature = signUserOp(sender, userOp); userOpHash = ENTRYPOINT.getUserOpHash(userOp); @@ -183,34 +188,30 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { PackedUserOperation memory userOp, Vm.Wallet memory signer, BiconomySponsorshipPaymaster paymaster, - uint128 paymasterValGasLimit, - uint128 paymasterPostOpGasLimit, - address paymasterId, - uint48 validUntil, - uint48 validAfter, - uint32 priceMarkup + PaymasterData memory pmData ) internal view returns (bytes memory finalPmData, bytes memory signature) { - // Initial paymaster data with zero signature + // // Initial paymaster data with zero signature bytes memory initialPmData = abi.encodePacked( address(paymaster), - paymasterValGasLimit, - paymasterPostOpGasLimit, - paymasterId, - validUntil, - validAfter, - priceMarkup, + pmData.validationGasLimit, + pmData.postOpGasLimit, + pmData.paymasterId, + pmData.validUntil, + pmData.validAfter, + pmData.priceMarkup, new bytes(65) // Zero signature ); // Update user operation with initial paymaster data userOp.paymasterAndData = initialPmData; + // userOp.paymasterAndData = "0x"; // Generate hash to be signed - bytes32 paymasterHash = paymaster.getHash(userOp, paymasterId, validUntil, validAfter, priceMarkup); + bytes32 paymasterHash = paymaster.getHash(userOp, pmData.paymasterId, pmData.validUntil, pmData.validAfter, pmData.priceMarkup); // Sign the hash signature = signMessage(signer, paymasterHash); @@ -219,12 +220,12 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { // Final paymaster data with the actual signature finalPmData = abi.encodePacked( address(paymaster), - paymasterValGasLimit, - paymasterPostOpGasLimit, - paymasterId, - validUntil, - validAfter, - priceMarkup, + pmData.validationGasLimit, + pmData.postOpGasLimit, + pmData.paymasterId, + pmData.validUntil, + pmData.validAfter, + pmData.priceMarkup, signature ); } @@ -293,6 +294,32 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { ); } + function generatePaymasterData( + BiconomySponsorshipPaymaster paymaster, + PaymasterData memory pmData + ) internal view returns (bytes memory) { + return abi.encodePacked( + address(paymaster), + pmData.validationGasLimit, + pmData.postOpGasLimit, + pmData.paymasterId, + pmData.validUntil, + pmData.validAfter, + pmData.priceMarkup, + new bytes(65) // Zero signature + ); + } + + function signPaymasterData(bytes32 paymasterHash, Vm.Wallet memory signer) + internal + view + returns (bytes memory) + { + bytes memory signature = signMessage(signer, paymasterHash); + require(signature.length == 65, "Invalid Paymaster Signature length"); + return signature; + } + function excludeLastNBytes(bytes memory data, uint256 n) internal pure returns (bytes memory) { require(data.length > n, "Input data is too short"); bytes memory result = new bytes(data.length - n); @@ -317,13 +344,9 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { uint256 totalGasFeesCharged = initialDappPaymasterBalance - resultingDappPaymasterBalance; - if (priceMarkup >= 1e6) { - //priceMarkup - expectedPriceMarkup = totalGasFeesCharged - ((totalGasFeesCharged * 1e6) / priceMarkup); - actualPriceMarkup = resultingFeeCollectorPaymasterBalance - initialFeeCollectorBalance; - } else { - revert("PriceMarkup must be more than 1e6"); - } + //priceMarkup + expectedPriceMarkup = totalGasFeesCharged - ((totalGasFeesCharged * 1e6) / priceMarkup); + actualPriceMarkup = resultingFeeCollectorPaymasterBalance - initialFeeCollectorBalance; } function calculateAndAssertAdjustments( @@ -353,6 +376,7 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { // TODO // Review: fix this properly. avoid out of stack errors assertGt(gasPaidByDapp, BUNDLER.addr.balance - initialBundlerBalance); + // Ensure that max 1% difference between total gas paid + the adjustment premium and gas paid by dapp (from // paymaster) assertApproxEqRel(totalGasFeePaid + actualPriceMarkup, gasPaidByDapp, 0.01e18); diff --git a/test/unit/concrete/TestSponsorshipPaymaster.t.sol b/test/unit/concrete/TestSponsorshipPaymaster.t.sol index a3ab24a..8de9045 100644 --- a/test/unit/concrete/TestSponsorshipPaymaster.t.sol +++ b/test/unit/concrete/TestSponsorshipPaymaster.t.sol @@ -13,44 +13,44 @@ contract TestSponsorshipPaymasterWithPriceMarkup is TestBase { setupPaymasterTestEnvironment(); // Deploy Sponsorship Paymaster bicoPaymaster = new BiconomySponsorshipPaymaster( - PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, PAYMASTER_FEE_COLLECTOR.addr, 7e3 + PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, PAYMASTER_FEE_COLLECTOR.addr, 27000 ); } function test_Deploy() external { BiconomySponsorshipPaymaster testArtifact = new BiconomySponsorshipPaymaster( - PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, PAYMASTER_FEE_COLLECTOR.addr, 7e3 + PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, PAYMASTER_FEE_COLLECTOR.addr, 27000 ); assertEq(testArtifact.owner(), PAYMASTER_OWNER.addr); assertEq(address(testArtifact.entryPoint()), ENTRYPOINT_ADDRESS); assertEq(testArtifact.verifyingSigner(), PAYMASTER_SIGNER.addr); assertEq(testArtifact.feeCollector(), PAYMASTER_FEE_COLLECTOR.addr); - assertEq(testArtifact.unaccountedGas(), 7e3); + assertEq(testArtifact.unaccountedGas(), 27000); } function test_RevertIf_DeployWithSignerSetToZero() external { vm.expectRevert(abi.encodeWithSelector(VerifyingSignerCanNotBeZero.selector)); new BiconomySponsorshipPaymaster( - PAYMASTER_OWNER.addr, ENTRYPOINT, address(0), PAYMASTER_FEE_COLLECTOR.addr, 7e3 + PAYMASTER_OWNER.addr, ENTRYPOINT, address(0), PAYMASTER_FEE_COLLECTOR.addr, 27000 ); } function test_RevertIf_DeployWithSignerAsContract() external { vm.expectRevert(abi.encodeWithSelector(VerifyingSignerCanNotBeContract.selector)); new BiconomySponsorshipPaymaster( - PAYMASTER_OWNER.addr, ENTRYPOINT, address(ENTRYPOINT), PAYMASTER_FEE_COLLECTOR.addr, 7e3 + PAYMASTER_OWNER.addr, ENTRYPOINT, address(ENTRYPOINT), PAYMASTER_FEE_COLLECTOR.addr, 27000 ); } function test_RevertIf_DeployWithFeeCollectorSetToZero() external { vm.expectRevert(abi.encodeWithSelector(FeeCollectorCanNotBeZero.selector)); - new BiconomySponsorshipPaymaster(PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, address(0), 7e3); + new BiconomySponsorshipPaymaster(PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, address(0), 27000); } function test_RevertIf_DeployWithFeeCollectorAsContract() external { vm.expectRevert(abi.encodeWithSelector(FeeCollectorCanNotBeContract.selector)); - new BiconomySponsorshipPaymaster(PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, address(ENTRYPOINT), 7e3); + new BiconomySponsorshipPaymaster(PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, address(ENTRYPOINT), 27000); } function test_RevertIf_DeployWithUnaccountedGasCostTooHigh() external { @@ -65,7 +65,7 @@ contract TestSponsorshipPaymasterWithPriceMarkup is TestBase { assertEq(address(bicoPaymaster.entryPoint()), ENTRYPOINT_ADDRESS); assertEq(bicoPaymaster.verifyingSigner(), PAYMASTER_SIGNER.addr); assertEq(bicoPaymaster.feeCollector(), PAYMASTER_FEE_COLLECTOR.addr); - assertEq(bicoPaymaster.unaccountedGas(), 7e3); + assertEq(bicoPaymaster.unaccountedGas(), 27000); } function test_OwnershipTransfer() external prankModifier(PAYMASTER_OWNER.addr) { @@ -204,13 +204,13 @@ contract TestSponsorshipPaymasterWithPriceMarkup is TestBase { bicoPaymaster.withdrawTo(payable(BOB_ADDRESS), 1 ether); } - function test_ValidatePaymasterAndPostOpWithoutPriceMarkup() external prankModifier(DAPP_ACCOUNT.addr) { + function test_ValidatePaymasterAndPostOpWithoutPriceMarkup() external { + startPrank(DAPP_ACCOUNT.addr); bicoPaymaster.depositFor{ value: 10 ether }(DAPP_ACCOUNT.addr); - // No adjustment - uint32 priceMarkup = 1e6; + stopPrank(); PackedUserOperation[] memory ops = new PackedUserOperation[](1); - (PackedUserOperation memory userOp, bytes32 userOpHash) = createUserOp(ALICE, bicoPaymaster, priceMarkup); + (PackedUserOperation memory userOp, bytes32 userOpHash) = createUserOp(ALICE, "", bicoPaymaster, 1e6); ops[0] = userOp; uint256 initialBundlerBalance = BUNDLER.addr.balance; @@ -221,7 +221,9 @@ contract TestSponsorshipPaymasterWithPriceMarkup is TestBase { // submit userops vm.expectEmit(true, false, true, true, address(bicoPaymaster)); emit IBiconomySponsorshipPaymaster.GasBalanceDeducted(DAPP_ACCOUNT.addr, 0, userOpHash); + startPrank(BUNDLER.addr); ENTRYPOINT.handleOps(ops, payable(BUNDLER.addr)); + stopPrank(); // Calculate and assert price markups and gas payments calculateAndAssertAdjustments( @@ -230,7 +232,7 @@ contract TestSponsorshipPaymasterWithPriceMarkup is TestBase { initialFeeCollectorBalance, initialBundlerBalance, initialPaymasterEpBalance, - priceMarkup + 1e6 ); } @@ -240,7 +242,7 @@ contract TestSponsorshipPaymasterWithPriceMarkup is TestBase { uint32 priceMarkup = 1e6 + 1e5; PackedUserOperation[] memory ops = new PackedUserOperation[](1); - (PackedUserOperation memory userOp, bytes32 userOpHash) = createUserOp(ALICE, bicoPaymaster, priceMarkup); + (PackedUserOperation memory userOp, bytes32 userOpHash) = createUserOp(ALICE, "", bicoPaymaster, priceMarkup); ops[0] = userOp; uint256 initialBundlerBalance = BUNDLER.addr.balance; @@ -273,8 +275,9 @@ contract TestSponsorshipPaymasterWithPriceMarkup is TestBase { uint48 validAfter = uint48(block.timestamp); PackedUserOperation memory userOp = buildUserOpWithCalldata(ALICE, "", address(VALIDATOR_MODULE)); + PaymasterData memory pmData = PaymasterData(3e6, 3e6, DAPP_ACCOUNT.addr, validUntil, validAfter, 1e6); (userOp.paymasterAndData,) = generateAndSignPaymasterData( - userOp, PAYMASTER_SIGNER, bicoPaymaster, 3e6, 3e6, DAPP_ACCOUNT.addr, validUntil, validAfter, 1e6 + userOp, PAYMASTER_SIGNER, bicoPaymaster, pmData ); userOp.paymasterAndData = excludeLastNBytes(userOp.paymasterAndData, 2); userOp.signature = signUserOp(ALICE, userOp); @@ -292,8 +295,9 @@ contract TestSponsorshipPaymasterWithPriceMarkup is TestBase { uint48 validAfter = uint48(block.timestamp); PackedUserOperation memory userOp = buildUserOpWithCalldata(ALICE, "", address(VALIDATOR_MODULE)); + PaymasterData memory pmData = PaymasterData(3e6, 3e6, DAPP_ACCOUNT.addr, validUntil, validAfter, 1e6); (userOp.paymasterAndData,) = generateAndSignPaymasterData( - userOp, PAYMASTER_SIGNER, bicoPaymaster, 3e6, 3e6, DAPP_ACCOUNT.addr, validUntil, validAfter, 1e6 + userOp, PAYMASTER_SIGNER, bicoPaymaster, pmData ); userOp.signature = signUserOp(ALICE, userOp); @@ -310,8 +314,9 @@ contract TestSponsorshipPaymasterWithPriceMarkup is TestBase { uint48 validAfter = uint48(block.timestamp); PackedUserOperation memory userOp = buildUserOpWithCalldata(ALICE, "", address(VALIDATOR_MODULE)); + PaymasterData memory pmData = PaymasterData(3e6, 3e6, DAPP_ACCOUNT.addr, validUntil, validAfter, 1e6); (userOp.paymasterAndData,) = generateAndSignPaymasterData( - userOp, PAYMASTER_SIGNER, bicoPaymaster, 3e6, 3e6, DAPP_ACCOUNT.addr, validUntil, validAfter, 1e6 + userOp, PAYMASTER_SIGNER, bicoPaymaster, pmData ); userOp.signature = signUserOp(ALICE, userOp); @@ -385,8 +390,9 @@ contract TestSponsorshipPaymasterWithPriceMarkup is TestBase { uint48 validAfter = uint48(block.timestamp); uint32 priceMarkup = 1e6; PackedUserOperation memory userOp = buildUserOpWithCalldata(ALICE, "", address(VALIDATOR_MODULE)); + PaymasterData memory pmData = PaymasterData(3e6, 3e6, paymasterId, validUntil, validAfter, priceMarkup); (bytes memory paymasterAndData, bytes memory signature) = generateAndSignPaymasterData( - userOp, PAYMASTER_SIGNER, bicoPaymaster, 3e6, 3e6, paymasterId, validUntil, validAfter, priceMarkup + userOp, PAYMASTER_SIGNER, bicoPaymaster, pmData ); ( diff --git a/test/unit/fuzz/TestFuzz_TestSponsorshipPaymaster.t.sol b/test/unit/fuzz/TestFuzz_TestSponsorshipPaymaster.t.sol index 577e827..11b750a 100644 --- a/test/unit/fuzz/TestFuzz_TestSponsorshipPaymaster.t.sol +++ b/test/unit/fuzz/TestFuzz_TestSponsorshipPaymaster.t.sol @@ -13,7 +13,7 @@ contract TestFuzz_SponsorshipPaymasterWithPriceMarkup is TestBase { setupPaymasterTestEnvironment(); // Deploy Sponsorship Paymaster bicoPaymaster = new BiconomySponsorshipPaymaster( - PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, PAYMASTER_FEE_COLLECTOR.addr, 7e3 + PAYMASTER_OWNER.addr, ENTRYPOINT, PAYMASTER_SIGNER.addr, PAYMASTER_FEE_COLLECTOR.addr, 27000 ); } @@ -97,7 +97,7 @@ contract TestFuzz_SponsorshipPaymasterWithPriceMarkup is TestBase { bicoPaymaster.depositFor{ value: 10 ether }(DAPP_ACCOUNT.addr); PackedUserOperation[] memory ops = new PackedUserOperation[](1); - (PackedUserOperation memory userOp, bytes32 userOpHash) = createUserOp(ALICE, bicoPaymaster, priceMarkup); + (PackedUserOperation memory userOp, bytes32 userOpHash) = createUserOp(ALICE, "", bicoPaymaster, priceMarkup); ops[0] = userOp; uint256 initialBundlerBalance = BUNDLER.addr.balance; @@ -110,7 +110,9 @@ contract TestFuzz_SponsorshipPaymasterWithPriceMarkup is TestBase { emit IBiconomySponsorshipPaymaster.PriceMarkupCollected(DAPP_ACCOUNT.addr, 0); vm.expectEmit(true, false, true, true, address(bicoPaymaster)); emit IBiconomySponsorshipPaymaster.GasBalanceDeducted(DAPP_ACCOUNT.addr, 0, userOpHash); + vm.startPrank(BUNDLER.addr); ENTRYPOINT.handleOps(ops, payable(BUNDLER.addr)); + vm.stopPrank(); // Calculate and assert price markups and gas payments calculateAndAssertAdjustments( @@ -133,8 +135,9 @@ contract TestFuzz_SponsorshipPaymasterWithPriceMarkup is TestBase { view { PackedUserOperation memory userOp = buildUserOpWithCalldata(ALICE, "", address(VALIDATOR_MODULE)); + PaymasterData memory pmData = PaymasterData(3e6, 3e6, paymasterId, validUntil, validAfter, priceMarkup); (bytes memory paymasterAndData, bytes memory signature) = generateAndSignPaymasterData( - userOp, PAYMASTER_SIGNER, bicoPaymaster, 3e6, 3e6, paymasterId, validUntil, validAfter, priceMarkup + userOp, PAYMASTER_SIGNER, bicoPaymaster, pmData ); (