diff --git a/contracts/libraries/TokenPaymasterParserLib.sol b/contracts/libraries/TokenPaymasterParserLib.sol index 406b817..aaae02a 100644 --- a/contracts/libraries/TokenPaymasterParserLib.sol +++ b/contracts/libraries/TokenPaymasterParserLib.sol @@ -12,9 +12,9 @@ library TokenPaymasterParserLib { function parsePaymasterAndData( bytes calldata paymasterAndData ) - external + internal pure - returns (IBiconomyTokenPaymaster.PaymasterMode mode, bytes memory modeSpecificData) + returns (IBiconomyTokenPaymaster.PaymasterMode mode, bytes calldata modeSpecificData) { unchecked { mode = IBiconomyTokenPaymaster.PaymasterMode(uint8(bytes1(paymasterAndData[PAYMASTER_MODE_OFFSET]))); @@ -25,15 +25,15 @@ library TokenPaymasterParserLib { function parseExternalModeSpecificData( bytes calldata modeSpecificData ) - external + internal pure returns ( uint48 validUntil, uint48 validAfter, address tokenAddress, - uint256 tokenPrice, // Review: why uint128 and not uint256. in independent mode it is uint256 + uint256 tokenPrice, uint32 externalPriceMarkup, - bytes memory signature + bytes calldata signature ) { validUntil = uint48(bytes6(modeSpecificData[:6])); @@ -47,7 +47,7 @@ library TokenPaymasterParserLib { function parseIndependentModeSpecificData( bytes calldata modeSpecificData ) - external + internal pure returns (address tokenAddress) { diff --git a/contracts/token/BiconomyTokenPaymaster.sol b/contracts/token/BiconomyTokenPaymaster.sol index 8638b4b..90b0d2a 100644 --- a/contracts/token/BiconomyTokenPaymaster.sol +++ b/contracts/token/BiconomyTokenPaymaster.sol @@ -474,7 +474,7 @@ contract BiconomyTokenPaymaster is override returns (bytes memory context, uint256 validationData) { - (PaymasterMode mode, bytes memory modeSpecificData) = userOp.paymasterAndData.parsePaymasterAndData(); + (PaymasterMode mode, bytes calldata modeSpecificData) = userOp.paymasterAndData.parsePaymasterAndData(); if (uint8(mode) > 1) { revert InvalidPaymasterMode(); diff --git a/contracts/token/swaps/Uniswapper.sol b/contracts/token/swaps/Uniswapper.sol index 2004d2e..205eb03 100644 --- a/contracts/token/swaps/Uniswapper.sol +++ b/contracts/token/swaps/Uniswapper.sol @@ -13,6 +13,8 @@ import "@uniswap/v3-periphery/contracts/interfaces/IPeripheryPayments.sol"; * @notice Based on Infinitism's Uniswap Helper contract */ abstract contract Uniswapper { + + event SwappingReverted(address tokenIn, uint256 amountIn, bytes reason); /// @notice The Uniswap V3 SwapRouter contract ISwapRouter public immutable uniswapRouter; @@ -65,9 +67,8 @@ abstract contract Uniswapper { try uniswapRouter.exactInputSingle(params) returns (uint256 _amountOut) { amountOut = _amountOut; - } catch { - // Review could emit an event here - // Uniswap Reverted + } catch (bytes memory reason) { + emit SwappingReverted(tokenIn, amountIn, reason); amountOut = 0; } } diff --git a/test/base/TestBase.sol b/test/base/TestBase.sol index a075945..23a4fb1 100644 --- a/test/base/TestBase.sol +++ b/test/base/TestBase.sol @@ -485,7 +485,7 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { uint256 gasPaidBySAInNativeTokens = gasPaidBySAInERC20 * 1e18 / tokenPrice; // Assert we never undercharge - assertGte(gasPaidBySAInNativeTokens, BUNDLER.addr.balance - initialBundlerBalance); + assertGe(gasPaidBySAInNativeTokens, BUNDLER.addr.balance - initialBundlerBalance); // Ensure that max 2% difference between what is should have been charged and what was charged // this difference comes from difference of postop gas and estimated postop gas (paymaster.unaccountedGas) @@ -510,14 +510,4 @@ abstract contract TestBase is CheatCodes, TestHelper, BaseEventsAndErrors { array[0] = oracle; return array; } -} -/* -1226028000000 -1794876000000 - -2921664000000 -3020904000000 - -1800000000000 max penalty - -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/test/mocks/PaymasterParserLibExposed.sol b/test/mocks/PaymasterParserLibExposed.sol new file mode 100644 index 0000000..41207ce --- /dev/null +++ b/test/mocks/PaymasterParserLibExposed.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Unlicensed +pragma solidity ^0.8.27; + +import { TokenPaymasterParserLib } from "../../contracts/libraries/TokenPaymasterParserLib.sol"; +import { IBiconomyTokenPaymaster } from "../../contracts/interfaces/IBiconomyTokenPaymaster.sol"; + +library PaymasterParserLibExposed { + using TokenPaymasterParserLib for bytes; + + function parsePaymasterAndData(bytes calldata paymasterAndData) public pure returns (IBiconomyTokenPaymaster.PaymasterMode mode, bytes calldata modeSpecificData) { + return paymasterAndData.parsePaymasterAndData(); + } + + function parseExternalModeSpecificData(bytes calldata modeSpecificData) public pure returns ( + uint48 validUntil, + uint48 validAfter, + address tokenAddress, + uint256 tokenPrice, + uint32 externalPriceMarkup, + bytes calldata signature + ) { + return modeSpecificData.parseExternalModeSpecificData(); + } + + function parseIndependentModeSpecificData(bytes calldata modeSpecificData) public pure returns (address tokenAddress) { + return modeSpecificData.parseIndependentModeSpecificData(); + } +} \ No newline at end of file diff --git a/test/mocks/PaymasterParserLibWrapper.sol b/test/mocks/PaymasterParserLibWrapper.sol new file mode 100644 index 0000000..72c3206 --- /dev/null +++ b/test/mocks/PaymasterParserLibWrapper.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Unlicensed +pragma solidity ^0.8.27; + +import { PaymasterParserLibExposed } from "./PaymasterParserLibExposed.sol"; +import { IBiconomyTokenPaymaster } from "../../contracts/interfaces/IBiconomyTokenPaymaster.sol"; + +contract PaymasterParserLibWrapper { + using PaymasterParserLibExposed for bytes; + + function parsePaymasterAndData(bytes calldata paymasterAndData) external pure returns (IBiconomyTokenPaymaster.PaymasterMode mode, bytes memory modeSpecificData) { + (mode, modeSpecificData) = paymasterAndData.parsePaymasterAndData(); + } + + function parseExternalModeSpecificData(bytes calldata modeSpecificData) external pure returns ( + uint48 validUntil, + uint48 validAfter, + address tokenAddress, + uint256 tokenPrice, + uint32 externalPriceMarkup, + bytes memory signature + ) { + (validUntil, validAfter, tokenAddress, tokenPrice, externalPriceMarkup, signature) = modeSpecificData.parseExternalModeSpecificData(); + } + + function parseIndependentModeSpecificData(bytes calldata modeSpecificData) external pure returns (address tokenAddress) { + tokenAddress = modeSpecificData.parseIndependentModeSpecificData(); + } +} \ No newline at end of file diff --git a/test/unit/concrete/TestTokenPaymaster.Base.t.sol b/test/unit/concrete/TestTokenPaymaster.Base.t.sol index c4ba592..d02ffbf 100644 --- a/test/unit/concrete/TestTokenPaymaster.Base.t.sol +++ b/test/unit/concrete/TestTokenPaymaster.Base.t.sol @@ -148,17 +148,17 @@ contract TestTokenPaymasterBase is TestBase { console2.log("initialTokenBalance", initialTokenBalance); uint256 initialDepositOnEntryPoint = tokenPaymaster.getDeposit(); - // vm.startPrank(address(tokenPaymaster)); - // usdc.approve(address(SWAP_ROUTER_ADDRESS), usdc.balanceOf(address(tokenPaymaster))); - // vm.stopPrank(); + vm.startPrank(address(tokenPaymaster)); + //usdc.approve(address(SWAP_ROUTER_ADDRESS), usdc.balanceOf(address(tokenPaymaster))); + vm.stopPrank(); // Review reason for failure startPrank(PAYMASTER_OWNER.addr); - tokenPaymaster.swapTokenAndDeposit(address(usdc), 1e6, 0); + tokenPaymaster.swapTokenAndDeposit(address(usdc), 99e6, 0); stopPrank(); - // uint256 newTokenBalance = usdc.balanceOf(address(tokenPaymaster)); - // assertEq(newTokenBalance, 0); + uint256 newTokenBalance = usdc.balanceOf(address(tokenPaymaster)); + assertEq(newTokenBalance, 0); // uint256 newDepositOnEntryPoint = tokenPaymaster.getDeposit(); // assertGt(newDepositOnEntryPoint, initialDepositOnEntryPoint); diff --git a/test/unit/concrete/TestTokenPaymasterParserLib.t.sol b/test/unit/concrete/TestTokenPaymasterParserLib.t.sol index be1b14f..326acfa 100644 --- a/test/unit/concrete/TestTokenPaymasterParserLib.t.sol +++ b/test/unit/concrete/TestTokenPaymasterParserLib.t.sol @@ -4,10 +4,16 @@ pragma solidity ^0.8.27; import "forge-std/Test.sol"; import "../../../contracts/libraries/TokenPaymasterParserLib.sol"; import { IBiconomyTokenPaymaster } from "../../../contracts/interfaces/IBiconomyTokenPaymaster.sol"; +import { PaymasterParserLibWrapper } from "../../mocks/PaymasterParserLibWrapper.sol"; // Mock contract to test the TokenPaymasterParserLib contract TestTokenPaymasterParserLib is Test { - using TokenPaymasterParserLib for bytes; + + PaymasterParserLibWrapper public parser; + + function setUp() public { + parser = new PaymasterParserLibWrapper(); + } function test_ParsePaymasterAndData_ExternalMode() public { // Simulate an example paymasterAndData for External Mode @@ -27,7 +33,7 @@ contract TestTokenPaymasterParserLib is Test { // Parse the paymasterAndData (IBiconomyTokenPaymaster.PaymasterMode parsedMode, bytes memory parsedModeSpecificData) = - paymasterAndData.parsePaymasterAndData(); + parser.parsePaymasterAndData(paymasterAndData); // Validate the mode and modeSpecificData assertEq(uint8(parsedMode), uint8(expectedMode), "Mode should match External"); @@ -52,7 +58,7 @@ contract TestTokenPaymasterParserLib is Test { // Parse the paymasterAndData (IBiconomyTokenPaymaster.PaymasterMode parsedMode, bytes memory parsedModeSpecificData) = - paymasterAndData.parsePaymasterAndData(); + parser.parsePaymasterAndData(paymasterAndData); // Validate the mode and modeSpecificData assertEq(uint8(parsedMode), uint8(expectedMode), "Mode should match Independent"); @@ -87,7 +93,7 @@ contract TestTokenPaymasterParserLib is Test { uint256 parsedTokenPrice, uint32 parsedExternalPriceMarkup, bytes memory parsedSignature - ) = externalModeSpecificData.parseExternalModeSpecificData(); + ) = parser.parseExternalModeSpecificData(externalModeSpecificData); // Validate the parsed values assertEq(parsedValidUntil, expectedValidUntil, "ValidUntil should match"); @@ -98,13 +104,13 @@ contract TestTokenPaymasterParserLib is Test { assertEq(parsedSignature, expectedSignature, "Signature should match"); } - function test_ParseIndependentModeSpecificData() public pure { + function test_ParseIndependentModeSpecificData() public view { // Simulate valid independent mode specific data address expectedTokenAddress = address(0x9876543210AbCDef9876543210ABCdEf98765432); bytes memory independentModeSpecificData = abi.encodePacked(bytes20(expectedTokenAddress)); // Parse the mode specific data - address parsedTokenAddress = independentModeSpecificData.parseIndependentModeSpecificData(); + address parsedTokenAddress = parser.parseIndependentModeSpecificData(independentModeSpecificData); // Validate the parsed token address assertEq(parsedTokenAddress, expectedTokenAddress, "Token address should match"); @@ -116,7 +122,7 @@ contract TestTokenPaymasterParserLib is Test { // Expect the test to revert due to invalid data length vm.expectRevert(); - invalidExternalModeSpecificData.parseExternalModeSpecificData(); + parser.parseExternalModeSpecificData(invalidExternalModeSpecificData); } function test_RevertIf_InvalidIndependentModeSpecificDataLength() public { @@ -125,6 +131,6 @@ contract TestTokenPaymasterParserLib is Test { // Expect the test to revert due to invalid data length vm.expectRevert(); - invalidIndependentModeSpecificData.parseIndependentModeSpecificData(); + parser.parseIndependentModeSpecificData(invalidIndependentModeSpecificData); } }