-
Notifications
You must be signed in to change notification settings - Fork 133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: handle one off bypassing paymaster and data middleware case #606
Conversation
packages/core/src/actions/smartAccount/internal/runMiddlewareStack.ts
Outdated
Show resolved
Hide resolved
@@ -51,7 +56,9 @@ export async function _runMiddlewareStack< | |||
client.middleware.feeEstimator, | |||
client.middleware.gasEstimator, | |||
client.middleware.customMiddleware, | |||
client.middleware.paymasterAndData, | |||
overrides && bypassPaymasterAndData(overrides) | |||
? bypassPaymasterMiddleware |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: just use the noopMiddleware
here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot. @moldy530 because for bypassing case for entrypoint v7, I need to unset all 4 paymaster fields of user op.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see comment below, why are they ever set if the override is 0x
then no code that handles paymaster should ever run and the gas estimator should never return paymaster fields. I would not expect to to have paymaster fields populated before the paymaster middleware runs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes it could, now that gas Estimator response includes paymasterVerificationGas, and this should be omitted for bypassing paymaster.
Thus, bypassmiddleware is not the same as noopmiddleware.
If paymaster is configured, gas Estimator response WILL include the paymasterVerificationGas field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now that gas Estimator response includes paymasterVerificationGas, and this should be omitted for bypassing paymaster
Why is that? it should respect the overrides.paymasterAndData === "0x"
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would expect that all middlewares that can return paymaster fields respect the paymasterAndData
override if it is passed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, @dphilipson just to confirm, if paymaster
address is not set on the user op struct sent for estimate user operation gas RPC, the bundler will never send the paymaster gas limits? Not just rundler, but all other bundlers. This is not clear on the 4337 standards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, the standard says, in the estimation response:
- paymasterVerificationGasLimit value used for paymaster verification (if paymaster exists in the UserOperation)
- paymasterPostOpGasLimit value used for paymaster post op execution (if paymaster exists in the UserOperation)
I would interpret that as saying that it doesn't return values if there's no paymaster, either omitting the fields entirely or returning null
. Our bundler does one of these, don't remember which (I would guess returning null).
I'm inclined to say it's okay to not go out of the way to delete the fields here and just trust whatever the bundler is returning. For one thing, I would expect any bundler which is returning zeroes for the paymaster fields when there's no paymaster would also accept zeroes for the paymaster fields when there's no paymaster, so it should be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if above where we have client.middleware.dummyPaymasterAndData
run we add the same check for the override and just noop then we don't need this bypassMiddleware at all and we can just run the noop middleware
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@moldy530 for entrypoint v0.6, don't we need to set paymasterAndData as '0x' for estimate gas step? or is that not needed? @dphilipson
packages/core/src/middleware/defaults/bypassPaymasterMiddleware.ts
Outdated
Show resolved
Hide resolved
8623f5c
to
27ffca4
Compare
packages/core/src/middleware/defaults/bypassPaymasterMiddleware.ts
Outdated
Show resolved
Hide resolved
updated the PR with: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me. Really appreciate all the doc comments. I'm not as familiar with the middleware stack as @moldy530 so I'd definitely appreciate a second look if he has a chance.
Question since I didn't notice it mentioned anywhere: do we also need to disable the dummyPaymasterAndData
middleware when there's a "0x" paymaster override?
@dphilipson we don't have control over the overridden dummy paymaster middleware. When the user sets the paymaster (for example gas manager), both dummy paymaster middleware and paymaster middleware is overridden. The dummy paymaster middleware is supposed to set the paymaster address + dummy data for the dummy paymaster middleware. (we should add this to our doc of using custom paymaster) |
Asana task https://app.asana.com/0/1205598840815267/1207162808443182/f for "The dummy paymaster middleware is supposed to set the paymaster address + dummy data for the dummy paymaster middleware. (we should add this to our doc of using custom paymaster)" @dphilipson |
wait why don't we just do what we do with dummyPaymaster? we can skip running dummy paymaster if the override is |
628e769
to
7207a52
Compare
7207a52
to
58ad449
Compare
packages/core/src/client/types.ts
Outdated
@@ -42,7 +42,7 @@ export type ClientMiddlewareConfig< | |||
"dummyPaymasterAndData" | "paymasterAndData" | |||
> & { | |||
paymasterAndData?: { | |||
dummyPaymasterAndData: () => Hex; | |||
dummyPaymasterAndData: ClientMiddlewareFn<TContext>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dphilipson @moldy530 this would be a breaking change for devs who are overriding this dummy paymaster and data middleware.
But this is necessary because from dummy paymaster and data, we need to check the entrypoint version from the account (either hoisted or passed in).
@moldy530 let me know if you have an idea for preventing breaking change for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had a question. If the answer is "no", then lgtm.
...struct, | ||
...(account.getEntryPoint().version === "0.7.0" | ||
? { | ||
paymaster: `${paymasterAddress}`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you not need to set paymasterData: dummyData
in this case?
breaking change: - dummyPaymasterAndData middleware override used to be () => Hex, but in this PR, changed to ClientMiddlewareFn just like all other middlewares. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we landed on the fact that you don't need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually want to resolve the discussion in slack, taking back my approval for now. Sorry!
6113ff8
to
18525a5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think it needs a hex concat fix, but otherwise I like it!
overrides.paymasterAndData!.dummyPaymasterAndData() | ||
) | ||
? parsePaymasterAndData( | ||
overrides.paymasterAndData!.dummyPaymasterAndData() as Hex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you put overrides.paymasterAndData!.dummyPaymasterAndData()
into a temp variable, you wouldn't need these casts because isHex
would work as a type guard (plus you wouldn't need to keep writing this large expression over and over). I'd suggest:
overrides.paymasterAndData?.dummyPaymasterAndData
? async (struct, { account }) => {
const data = overrides.paymasterAndData!.dummyPaymasterAndData();
return account.getEntryPoint().version === "0.7.0"
? {
...struct,
...(isHex(data)
? parsePaymasterAndData(data)
: concatPayamsterAndData(data)
),
}
// ...
and maybe consider turning some of ternaries into if-else blocks for readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isHex would work as a type guard
Actually it doesn't which is why had to cast...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It didn't work before because you're evaluating dummyPaymasterAndData()
multiple times, so the type system can't tell that it's the same value. isHex
should work as a type guard if you extract the value, its signature is
function isHex(
value: unknown,
{ strict = true }: { strict?: boolean } = {},
): value is Hex;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's what it looks like without the casts using isHex
as a type guard, if you want it. Verified locally.
dummyPaymasterAndData: overrides.paymasterAndData?.dummyPaymasterAndData
? async (struct, { account }) => {
const data = overrides.paymasterAndData!.dummyPaymasterAndData();
const paymasterOverrides =
account.getEntryPoint().version === "0.7.0"
? isHex(data)
? parsePaymasterAndData(data)
: data
: {
paymasterAndData: isHex(data)
? data
: concatPaymasterAndData(data),
};
return { ...struct, ...paymasterOverrides };
}
: defaultPaymasterAndData,
packages/core/src/actions/smartAccount/internal/runMiddlewareStack.ts
Outdated
Show resolved
Hide resolved
packages/core/src/actions/smartAccount/internal/runMiddlewareStack.ts
Outdated
Show resolved
Hide resolved
packages/core/src/middleware/defaults/bypassPaymasterMiddleware.ts
Outdated
Show resolved
Hide resolved
18525a5
to
5f0fd50
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think you have a hex conversion bug. If we get that fixed I think we're there.
overrides.paymasterAndData!.dummyPaymasterAndData() | ||
) | ||
? parsePaymasterAndData( | ||
overrides.paymasterAndData!.dummyPaymasterAndData() as Hex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's what it looks like without the casts using isHex
as a type guard, if you want it. Verified locally.
dummyPaymasterAndData: overrides.paymasterAndData?.dummyPaymasterAndData
? async (struct, { account }) => {
const data = overrides.paymasterAndData!.dummyPaymasterAndData();
const paymasterOverrides =
account.getEntryPoint().version === "0.7.0"
? isHex(data)
? parsePaymasterAndData(data)
: data
: {
paymasterAndData: isHex(data)
? data
: concatPaymasterAndData(data),
};
return { ...struct, ...paymasterOverrides };
}
: defaultPaymasterAndData,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotta change the docs for he dummy paymaster and data to what it was before + the new union type
5f0fd50
to
03c179e
Compare
updated thanks for the thorough review! @dphilipson @moldy530 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! I would still consider my suggested change with calling dummyPaymasterAndData
once, not just because it doesn't need casts but also because calling a user-provided function once instead of multiple times can be a bit better e.g. if they add log statements to it for debugging, but I won't block because of that.
@dphilipson udpated per your suggestion. Thanks! |
03c179e
to
9408c65
Compare
breaking change: - dummyPaymasterAndData middleware override used to be () => Hex, but in this PR, changed to ClientMiddlewareFn just like all other middlewares.
Update: breaking change avoided with dummyPaymasterAndData middleware override being changed to:
To make it not breaking change, and also make it not as confusing for entrypoint v0.7 operations.
on the next major version update, we (should) would change the override.dummyPaymasterAndData to be
ClientMiddlewareFn
as well like other middleware.e2e test for simple account with entrypoint v0.7 and alchemy smart account client + gas manager passes. cc: @dphilipson @moldy530
Pull Request Checklist
yarn test
)site
folder, and guidelines for updating/adding docs can be found in the contribution guide)feat!: breaking change
)yarn lint:check
) and fix any issues? (yarn lint:write
)PR-Codex overview
This PR introduces enhancements to paymaster and data handling in various middleware functions and user operation structures.
Detailed summary
bypassPaymasterAndData
andconcatPaymasterAndData
dummyPaymasterAndData
type in multiple filesparsePaymasterAndData
functionUserOperationRequest
types in multiple files