Skip to content

Commit 7889a58

Browse files
committed
Add optional support for any bundler
1 parent 02628c7 commit 7889a58

File tree

1 file changed

+19
-16
lines changed

1 file changed

+19
-16
lines changed

src/LimitingPaymaster.sol

+19-16
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ contract LimitingPaymaster is BasePaymaster {
2121

2222
address public immutable verifyingSigner;
2323

24-
uint256 private constant VALID_TIMESTAMP_OFFSET = 20;
25-
uint256 private constant SIGNATURE_OFFSET = VALID_TIMESTAMP_OFFSET + 64;
26-
uint256 private constant SPENT_KEY_OFFSET = SIGNATURE_OFFSET + 65;
27-
2824
mapping (uint32 => uint96) public spent;
2925
mapping (address => bool) public bundlerAllowed;
3026

@@ -68,13 +64,16 @@ contract LimitingPaymaster is BasePaymaster {
6864
* verify our external signer signed this request.
6965
* the "paymasterAndData" is expected to be the paymaster and a signature over the entire request params
7066
* paymasterAndData[:20] : address(this)
71-
* paymasterAndData[20:84] : abi.encode(validUntil, validAfter)
72-
* paymasterAndData[84:] : signature
73-
* paymasterAndData[149:213] : abi.encode(spentKey, spentMax)
67+
* paymasterAndData[20:26] : validUntil
68+
* paymasterAndData[26:32] : validAfter
69+
* paymasterAndData[32:97] : signature
70+
* paymasterAndData[97:101] : spendKey
71+
* paymasterAndData[101:113] : spendMax
72+
* paymasterAndData[113] : allowAnyBundler
7473
*/
7574
function _validatePaymasterUserOp(UserOperation calldata userOp, bytes32 /*userOpHash*/, uint256 requiredPreFund)
7675
internal view override returns (bytes memory context, uint256 validationData) {
77-
(uint48 validUntil, uint48 validAfter, bytes calldata signature, uint32 spentKey, uint96 spentMax) = parsePaymasterAndData(userOp.paymasterAndData);
76+
(uint48 validUntil, uint48 validAfter, bytes calldata signature, uint32 spentKey, uint96 spentMax, bool allowAnyBundler) = parsePaymasterAndData(userOp.paymasterAndData);
7877
require(spent[spentKey] + requiredPreFund <= spentMax, "Paymaster: spender funds are depleted");
7978
// Only support 65-byte signatures, to avoid potential replay attacks.
8079
require(signature.length == 65, "Paymaster: invalid signature length in paymasterAndData");
@@ -87,23 +86,27 @@ contract LimitingPaymaster is BasePaymaster {
8786

8887
// no need for other on-chain validation: entire UserOp should have been checked
8988
// by the external service prior to signing it.
90-
return (abi.encode(spentKey), _packValidationData(false, validUntil, validAfter));
89+
return (abi.encode(spentKey, allowAnyBundler), _packValidationData(false, validUntil, validAfter));
9190
}
9291

9392
function _postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) internal override {
93+
(uint32 spentKey, bool allowAnyBundler) = abi.decode(context, (uint32, bool));
94+
// unfortunately tx.origin is not allowed in validation, so we check here
95+
require(allowAnyBundler || bundlerAllowed[tx.origin], "Paymaster: bundler not allowed");
96+
9497
if (mode != PostOpMode.postOpReverted) {
95-
// unfortunately tx.origin is not allowed in validation, so we check here
96-
require(bundlerAllowed[tx.origin], "Paymaster: bundler not allowed");
97-
(uint32 spentKey) = abi.decode(context, (uint32));
9898
spent[spentKey] += uint96(actualGasCost);
9999
}
100100
}
101101

102102
function parsePaymasterAndData(bytes calldata paymasterAndData)
103-
internal pure returns(uint48 validUntil, uint48 validAfter, bytes calldata signature, uint32 spentKey, uint96 spentMax) {
104-
(validUntil, validAfter) = abi.decode(paymasterAndData[VALID_TIMESTAMP_OFFSET:SIGNATURE_OFFSET], (uint48, uint48));
105-
signature = paymasterAndData[SIGNATURE_OFFSET:SPENT_KEY_OFFSET];
106-
(spentKey, spentMax) = abi.decode(paymasterAndData[SPENT_KEY_OFFSET:], (uint32, uint96));
103+
internal pure returns(uint48 validUntil, uint48 validAfter, bytes calldata signature, uint32 spentKey, uint96 spentMax, bool allowAnyBundler) {
104+
validUntil = uint48(bytes6(paymasterAndData[20:26]));
105+
validAfter = uint48(bytes6(paymasterAndData[26:32]));
106+
signature = paymasterAndData[32:97];
107+
spentKey = uint32(bytes4(paymasterAndData[97:101]));
108+
spentMax = uint96(bytes12(paymasterAndData[101:113]));
109+
allowAnyBundler = paymasterAndData.length > 113 && paymasterAndData[113] > 0;
107110
}
108111

109112
function renounceOwnership() public override view onlyOwner {

0 commit comments

Comments
 (0)