Skip to content

Commit ed67088

Browse files
committed
feat: insert permit for erc20 paymaster
1 parent f1ea3be commit ed67088

File tree

1 file changed

+79
-5
lines changed

1 file changed

+79
-5
lines changed

account-kit/infra/src/middleware/gasManager.ts

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
noopMiddleware,
2121
resolveProperties,
2222
} from "@aa-sdk/core";
23-
import { fromHex, isHex, type Hex } from "viem";
23+
import { fromHex, isHex, toHex, type Hex } from "viem";
2424
import type { AlchemySmartAccountClient } from "../client/smartAccountClient.js";
2525
import type { AlchemyTransport } from "../alchemyTransport.js";
2626
import { alchemyFeeEstimator } from "./feeEstimator.js";
@@ -62,7 +62,10 @@ interface AlchemyGasAndPaymasterAndDataMiddlewareParams {
6262

6363
export type PolicyToken = {
6464
address: string;
65+
maxTokenAmount: bigint;
6566
approvalMode: ApprovalMode;
67+
erc20Name: string;
68+
version: string;
6669
};
6770

6871
export enum ApprovalMode {
@@ -205,6 +208,79 @@ export function alchemyGasAndPaymasterAndDataMiddleware(
205208
: {}),
206209
});
207210

211+
let erc20Context = undefined;
212+
if (
213+
policyToken !== undefined &&
214+
policyToken.approvalMode == ApprovalMode.PERMIT
215+
) {
216+
// get a paymaster address
217+
let paymasterAddress = "0x";
218+
const paymasterData = await (
219+
client as AlchemySmartAccountClient
220+
).request({
221+
method: "pm_getPaymasterStubData",
222+
params: [
223+
userOp,
224+
account.getEntryPoint().address,
225+
toHex(client.chain.id),
226+
{
227+
policyId: Array.isArray(policyId) ? policyId[0] : policyId,
228+
},
229+
],
230+
});
231+
paymasterAddress = paymasterData.paymaster
232+
? paymasterData.paymaster
233+
: paymasterData.paymasterAndData
234+
? paymasterData.paymasterAndData.slice(0, 42)
235+
: "0x";
236+
const typed_permit_data = {
237+
types: {
238+
Permit: [
239+
{
240+
name: "owner",
241+
type: "address",
242+
},
243+
{
244+
name: "spender",
245+
type: "address",
246+
},
247+
{
248+
name: "value",
249+
type: "uint256",
250+
},
251+
{
252+
name: "nonce",
253+
type: "uint256",
254+
},
255+
{
256+
name: "deadline",
257+
type: "uint256",
258+
},
259+
],
260+
},
261+
primaryType: "Permit",
262+
domain: {
263+
name: policyToken.erc20Name,
264+
version: policyToken.version,
265+
chainId: client.chain.id,
266+
verifyingContract: policyToken.address as Hex,
267+
},
268+
message: {
269+
owner: account.address as Hex,
270+
spender: paymasterAddress as Hex,
271+
value: policyToken.maxTokenAmount,
272+
nonce: (await account.getAccountNonce()) + BigInt(1),
273+
deadline: BigInt(0xffffffffffffffffffffffffffffffff),
274+
},
275+
} as const;
276+
277+
erc20Context = {
278+
tokenAddress: policyToken.address,
279+
permit: client.account?.signTypedData(typed_permit_data),
280+
maxTokenAmount: policyToken.maxTokenAmount,
281+
};
282+
}
283+
208284
const result = await (client as AlchemySmartAccountClient).request({
209285
method: "alchemy_requestGasAndPaymasterAndData",
210286
params: [
@@ -214,11 +290,9 @@ export function alchemyGasAndPaymasterAndDataMiddleware(
214290
userOperation: userOp,
215291
dummySignature: await account.getDummySignature(),
216292
overrides,
217-
...(policyToken
293+
...(erc20Context
218294
? {
219-
erc20Context: {
220-
tokenAddress: policyToken.address,
221-
},
295+
erc20Context: erc20Context,
222296
}
223297
: {}),
224298
},

0 commit comments

Comments
 (0)