permissionless 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/_cjs/actions/pimlico/getTokenQuotes.js +6 -0
- package/_cjs/actions/pimlico/getTokenQuotes.js.map +1 -1
- package/_cjs/actions/public/getSenderAddress.js +9 -0
- package/_cjs/actions/public/getSenderAddress.js.map +1 -1
- package/_cjs/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.js +42 -1
- package/_cjs/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.js.map +1 -1
- package/_cjs/utils/erc20AllowanceOverride.js +36 -0
- package/_cjs/utils/erc20AllowanceOverride.js.map +1 -0
- package/_cjs/utils/erc20BalanceOverride.js +26 -0
- package/_cjs/utils/erc20BalanceOverride.js.map +1 -0
- package/_cjs/utils/index.js +5 -1
- package/_cjs/utils/index.js.map +1 -1
- package/_esm/actions/pimlico/getTokenQuotes.js +6 -0
- package/_esm/actions/pimlico/getTokenQuotes.js.map +1 -1
- package/_esm/actions/public/getSenderAddress.js +9 -0
- package/_esm/actions/public/getSenderAddress.js.map +1 -1
- package/_esm/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.js +43 -2
- package/_esm/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.js.map +1 -1
- package/_esm/utils/erc20AllowanceOverride.js +33 -0
- package/_esm/utils/erc20AllowanceOverride.js.map +1 -0
- package/_esm/utils/erc20BalanceOverride.js +23 -0
- package/_esm/utils/erc20BalanceOverride.js.map +1 -0
- package/_esm/utils/index.js +3 -1
- package/_esm/utils/index.js.map +1 -1
- package/_types/actions/pimlico/getTokenQuotes.d.ts +2 -0
- package/_types/actions/pimlico/getTokenQuotes.d.ts.map +1 -1
- package/_types/actions/public/getSenderAddress.d.ts.map +1 -1
- package/_types/clients/decorators/smartAccount.d.ts +5 -0
- package/_types/clients/decorators/smartAccount.d.ts.map +1 -1
- package/_types/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.d.ts +5 -1
- package/_types/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.d.ts.map +1 -1
- package/_types/types/pimlico.d.ts +2 -0
- package/_types/types/pimlico.d.ts.map +1 -1
- package/_types/utils/erc20AllowanceOverride.d.ts +10 -0
- package/_types/utils/erc20AllowanceOverride.d.ts.map +1 -0
- package/_types/utils/erc20BalanceOverride.d.ts +9 -0
- package/_types/utils/erc20BalanceOverride.d.ts.map +1 -0
- package/_types/utils/index.d.ts +3 -1
- package/_types/utils/index.d.ts.map +1 -1
- package/actions/pimlico/getTokenQuotes.ts +8 -0
- package/actions/public/getSenderAddress.ts +12 -0
- package/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.test.ts +88 -0
- package/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.ts +67 -1
- package/package.json +9 -3
- package/types/pimlico.ts +2 -0
- package/utils/erc20AllowanceOverride.test.ts +59 -0
- package/utils/erc20AllowanceOverride.ts +66 -0
- package/utils/erc20BalanceOverride.test.ts +57 -0
- package/utils/erc20BalanceOverride.ts +49 -0
- package/utils/index.ts +13 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pimlico.d.ts","sourceRoot":"","sources":["../../types/pimlico.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAE7D,KAAK,2CAA2C,GAAG;IAC/C,IAAI,EAAE;QACF,YAAY,EAAE,GAAG,CAAA;QACjB,oBAAoB,EAAE,GAAG,CAAA;KAC5B,CAAA;IACD,QAAQ,EAAE;QACN,YAAY,EAAE,GAAG,CAAA;QACjB,oBAAoB,EAAE,GAAG,CAAA;KAC5B,CAAA;IACD,IAAI,EAAE;QACF,YAAY,EAAE,GAAG,CAAA;QACjB,oBAAoB,EAAE,GAAG,CAAA;KAC5B,CAAA;CACJ,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IACrC,MAAM,EACA,WAAW,GACX,eAAe,GACf,WAAW,GACX,UAAU,GACV,UAAU,GACV,UAAU,GACV,QAAQ,CAAA;IACd,eAAe,EAAE,IAAI,GAAG,IAAI,CAAA;CAC/B,CAAA;AAED,KAAK,6BAA6B,GAAG;IACjC,MAAM,EAAE;QACJ,SAAS,EAAE,OAAO,CAAA;QAClB,KAAK,EAAE,OAAO,CAAA;QACd,SAAS,EAAE,GAAG,CAAA;QACd,YAAY,EAAE,GAAG,CAAA;QACjB,uBAAuB,EAAE,GAAG,CAAA;
|
|
1
|
+
{"version":3,"file":"pimlico.d.ts","sourceRoot":"","sources":["../../types/pimlico.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAE7D,KAAK,2CAA2C,GAAG;IAC/C,IAAI,EAAE;QACF,YAAY,EAAE,GAAG,CAAA;QACjB,oBAAoB,EAAE,GAAG,CAAA;KAC5B,CAAA;IACD,QAAQ,EAAE;QACN,YAAY,EAAE,GAAG,CAAA;QACjB,oBAAoB,EAAE,GAAG,CAAA;KAC5B,CAAA;IACD,IAAI,EAAE;QACF,YAAY,EAAE,GAAG,CAAA;QACjB,oBAAoB,EAAE,GAAG,CAAA;KAC5B,CAAA;CACJ,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IACrC,MAAM,EACA,WAAW,GACX,eAAe,GACf,WAAW,GACX,UAAU,GACV,UAAU,GACV,UAAU,GACV,QAAQ,CAAA;IACd,eAAe,EAAE,IAAI,GAAG,IAAI,CAAA;CAC/B,CAAA;AAED,KAAK,6BAA6B,GAAG;IACjC,MAAM,EAAE;QACJ,SAAS,EAAE,OAAO,CAAA;QAClB,KAAK,EAAE,OAAO,CAAA;QACd,SAAS,EAAE,GAAG,CAAA;QACd,YAAY,EAAE,GAAG,CAAA;QACjB,uBAAuB,EAAE,GAAG,CAAA;QAC5B,WAAW,CAAC,EAAE,GAAG,CAAA;QACjB,aAAa,CAAC,EAAE,GAAG,CAAA;KACtB,EAAE,CAAA;CACN,CAAA;AAED,MAAM,MAAM,gBAAgB,CACxB,iBAAiB,SAAS,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,IACvD;IACA;QACI,MAAM,EAAE,kCAAkC,CAAA;QAC1C,UAAU,EAAE,EAAE,CAAA;QACd,UAAU,EAAE,2CAA2C,CAAA;KAC1D;IACD;QACI,MAAM,EAAE,gCAAgC,CAAA;QACxC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QACxB,UAAU,EAAE,0BAA0B,CAAA;KACzC;IACD;QACI,MAAM,EAAE,qCAAqC,CAAA;QAC7C,UAAU,EAAE;YACR,uBAAuB,EAAE,GAAG;YAC5B,eAAe,EAAE,OAAO;YACxB,UAAU,EAAE,OAAO;SACtB,CAAA;QACD,UAAU,EAAE,IAAI,CAAA;KACnB;IACD;QACI,MAAM,EAAE,yBAAyB,CAAA;QACjC,UAAU,EAAE;YACR,aAAa,EAAE,KAAK,CACd,CAAC,iBAAiB,SAAS,KAAK,GAC1B,SAAS,CACL,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,EACvB,cAAc,GACd,oBAAoB,GACpB,sBAAsB,CAC3B,GACD,KAAK,CAAC,GACZ,CAAC,iBAAiB,SAAS,KAAK,GAC1B,SAAS,CACL,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,EACvB,cAAc,GACd,oBAAoB,GACpB,sBAAsB,GACtB,+BAA+B,GAC/B,yBAAyB,CAC9B,GACD,KAAK,CAAC,CACjB;YACD,UAAU,EAAE,OAAO;YACnB,QAAQ,CAAC,EAAE;gBACP,mBAAmB,CAAC,EAAE,MAAM,CAAA;aAC/B;SACJ,CAAA;QACD,UAAU,EAAE,iBAAiB,SAAS,KAAK,GACrC;YACI,gBAAgB,EAAE,GAAG,CAAA;YACrB,kBAAkB,EAAE,GAAG,CAAA;YACvB,oBAAoB,EAAE,GAAG,CAAA;YACzB,YAAY,EAAE,GAAG,CAAA;YACjB,SAAS,CAAC,EAAE,KAAK,CAAA;YACjB,6BAA6B,CAAC,EAAE,KAAK,CAAA;YACrC,uBAAuB,CAAC,EAAE,KAAK,CAAA;YAC/B,aAAa,CAAC,EAAE,KAAK,CAAA;SACxB,GACD;YACI,kBAAkB,EAAE,GAAG,CAAA;YACvB,oBAAoB,EAAE,GAAG,CAAA;YACzB,YAAY,EAAE,GAAG,CAAA;YACjB,SAAS,EAAE,OAAO,CAAA;YAClB,6BAA6B,EAAE,GAAG,CAAA;YAClC,uBAAuB,EAAE,GAAG,CAAA;YAC5B,aAAa,EAAE,GAAG,CAAA;YAClB,gBAAgB,CAAC,EAAE,KAAK,CAAA;SAC3B,CAAA;KACV;IACD;QACI,MAAM,EAAE,gCAAgC,CAAA;QACxC,UAAU,EAAE;YACR,aAAa,EAAE,aAAa,CAAC,iBAAiB,EAAE,GAAG,CAAC;YACpD,UAAU,EAAE,OAAO;YACnB,oBAAoB,EAAE,MAAM,EAAE;SACjC,CAAA;QACD,UAAU,EAAE;YACR,mBAAmB,EAAE,MAAM,CAAA;YAC3B,IAAI,EAAE;gBACF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;gBACnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;gBACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;gBACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;aAC7B,CAAA;SACJ,EAAE,CAAA;KACN;IACD;QACI,MAAM,EAAE,wBAAwB,CAAA;QAChC,UAAU,EAAE,CAAC;YAAE,MAAM,EAAE,OAAO,EAAE,CAAA;SAAE,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;QACtE,UAAU,EAAE,6BAA6B,CAAA;KAC5C;CACJ,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Address, type StateOverride } from "viem";
|
|
2
|
+
export type Erc20AllowanceOverrideParameters = {
|
|
3
|
+
token: Address;
|
|
4
|
+
owner: Address;
|
|
5
|
+
spender: Address;
|
|
6
|
+
slot: bigint;
|
|
7
|
+
amount?: bigint;
|
|
8
|
+
};
|
|
9
|
+
export declare function erc20AllowanceOverride({ token, owner, spender, slot, amount }: Erc20AllowanceOverrideParameters): StateOverride;
|
|
10
|
+
//# sourceMappingURL=erc20AllowanceOverride.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"erc20AllowanceOverride.d.ts","sourceRoot":"","sources":["../../utils/erc20AllowanceOverride.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,OAAO,EACZ,KAAK,aAAa,EAIrB,MAAM,MAAM,CAAA;AAEb,MAAM,MAAM,gCAAgC,GAAG;IAC3C,KAAK,EAAE,OAAO,CAAA;IACd,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,wBAAgB,sBAAsB,CAAC,EACnC,KAAK,EACL,KAAK,EACL,OAAO,EACP,IAAI,EACJ,MAEC,EACJ,EAAE,gCAAgC,GAAG,aAAa,CAyClD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Address, type StateOverride } from "viem";
|
|
2
|
+
export type Erc20BalanceOverrideParameters = {
|
|
3
|
+
token: Address;
|
|
4
|
+
owner: Address;
|
|
5
|
+
slot: bigint;
|
|
6
|
+
balance?: bigint;
|
|
7
|
+
};
|
|
8
|
+
export declare function erc20BalanceOverride({ token, owner, slot, balance }: Erc20BalanceOverrideParameters): StateOverride;
|
|
9
|
+
//# sourceMappingURL=erc20BalanceOverride.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"erc20BalanceOverride.d.ts","sourceRoot":"","sources":["../../utils/erc20BalanceOverride.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,OAAO,EACZ,KAAK,aAAa,EAIrB,MAAM,MAAM,CAAA;AAEb,MAAM,MAAM,8BAA8B,GAAG;IACzC,KAAK,EAAE,OAAO,CAAA;IACd,KAAK,EAAE,OAAO,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,wBAAgB,oBAAoB,CAAC,EACjC,KAAK,EACL,KAAK,EACL,IAAI,EACJ,OAEC,EACJ,EAAE,8BAA8B,GAAG,aAAa,CA0BhD"}
|
package/_types/utils/index.d.ts
CHANGED
|
@@ -8,5 +8,7 @@ import { encodeNonce } from "./encodeNonce";
|
|
|
8
8
|
import { type EncodeInstallModuleParameters, encodeInstallModule } from "./encodeInstallModule";
|
|
9
9
|
import { getPackedUserOperation } from "./getPackedUserOperation";
|
|
10
10
|
import { type EncodeCallDataParams, encode7579Calls } from "./encode7579Calls";
|
|
11
|
-
|
|
11
|
+
import { type Erc20AllowanceOverrideParameters, erc20AllowanceOverride } from "./erc20AllowanceOverride";
|
|
12
|
+
import { type Erc20BalanceOverrideParameters, erc20BalanceOverride } from "./erc20BalanceOverride";
|
|
13
|
+
export { transactionReceiptStatus, deepHexlify, getRequiredPrefund, toOwner, type GetRequiredPrefundReturnType, isSmartAccountDeployed, getAddressFromInitCodeOrPaymasterAndData, getPackedUserOperation, encodeNonce, decodeNonce, type EncodeInstallModuleParameters, encodeInstallModule, type EncodeCallDataParams, encode7579Calls, erc20AllowanceOverride, erc20BalanceOverride, type Erc20AllowanceOverrideParameters, type Erc20BalanceOverrideParameters };
|
|
12
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA;AACrE,OAAO,EAAE,wCAAwC,EAAE,MAAM,4CAA4C,CAAA;AACrG,OAAO,EACH,KAAK,4BAA4B,EACjC,kBAAkB,EACrB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE3C,OAAO,EACH,KAAK,6BAA6B,EAClC,mBAAmB,EACtB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,EAAE,KAAK,oBAAoB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA;AACrE,OAAO,EAAE,wCAAwC,EAAE,MAAM,4CAA4C,CAAA;AACrG,OAAO,EACH,KAAK,4BAA4B,EACjC,kBAAkB,EACrB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE3C,OAAO,EACH,KAAK,6BAA6B,EAClC,mBAAmB,EACtB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,EAAE,KAAK,oBAAoB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAC9E,OAAO,EACH,KAAK,gCAAgC,EACrC,sBAAsB,EACzB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACH,KAAK,8BAA8B,EACnC,oBAAoB,EACvB,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EACH,wBAAwB,EACxB,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,KAAK,4BAA4B,EACjC,sBAAsB,EACtB,wCAAwC,EACxC,sBAAsB,EACtB,WAAW,EACX,WAAW,EACX,KAAK,6BAA6B,EAClC,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,KAAK,gCAAgC,EACrC,KAAK,8BAA8B,EACtC,CAAA"}
|
|
@@ -25,6 +25,8 @@ export type GetTokenQuotesReturnType = {
|
|
|
25
25
|
postOpGas: bigint
|
|
26
26
|
exchangeRate: bigint
|
|
27
27
|
exchangeRateNativeToUsd: bigint
|
|
28
|
+
balanceSlot?: bigint
|
|
29
|
+
allowanceSlot?: bigint
|
|
28
30
|
}[]
|
|
29
31
|
|
|
30
32
|
/**
|
|
@@ -62,6 +64,12 @@ export const getTokenQuotes = async <
|
|
|
62
64
|
|
|
63
65
|
return res.quotes.map((quote) => ({
|
|
64
66
|
...quote,
|
|
67
|
+
balanceSlot: quote.balanceSlot
|
|
68
|
+
? hexToBigInt(quote.balanceSlot)
|
|
69
|
+
: undefined,
|
|
70
|
+
allowanceSlot: quote.allowanceSlot
|
|
71
|
+
? hexToBigInt(quote.allowanceSlot)
|
|
72
|
+
: undefined,
|
|
65
73
|
postOpGas: hexToBigInt(quote.postOpGas),
|
|
66
74
|
exchangeRate: hexToBigInt(quote.exchangeRate),
|
|
67
75
|
exchangeRateNativeToUsd: hexToBigInt(quote.exchangeRateNativeToUsd)
|
|
@@ -133,6 +133,18 @@ export const getSenderAddress = async (
|
|
|
133
133
|
err instanceof UnknownRpcError
|
|
134
134
|
)
|
|
135
135
|
|
|
136
|
+
if (!revertError) {
|
|
137
|
+
const cause = (e as ContractFunctionExecutionErrorType).cause as any
|
|
138
|
+
const errorName = cause?.data?.errorName ?? ""
|
|
139
|
+
if (
|
|
140
|
+
errorName === "SenderAddressResult" &&
|
|
141
|
+
cause?.data?.args &&
|
|
142
|
+
cause?.data?.args[0]
|
|
143
|
+
) {
|
|
144
|
+
return cause.data?.args[0] as Address
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
136
148
|
if (revertError instanceof ContractFunctionRevertedError) {
|
|
137
149
|
const errorName = revertError.data?.errorName ?? ""
|
|
138
150
|
if (
|
|
@@ -191,5 +191,93 @@ describe.each(getCoreSmartAccounts())(
|
|
|
191
191
|
expect(FINAL_ETH_BALANCE).toEqual(INTIAL_ETH_BALANCE) // There should be no ETH balance change
|
|
192
192
|
}
|
|
193
193
|
)
|
|
194
|
+
|
|
195
|
+
testWithRpc.skipIf(!supportsEntryPointV07)(
|
|
196
|
+
"prepareUserOperationForErc20Paymaster_v07",
|
|
197
|
+
async ({ rpc }) => {
|
|
198
|
+
const { anvilRpc } = rpc
|
|
199
|
+
|
|
200
|
+
const account = (
|
|
201
|
+
await getSmartAccountClient({
|
|
202
|
+
entryPoint: {
|
|
203
|
+
version: "0.7"
|
|
204
|
+
},
|
|
205
|
+
...rpc
|
|
206
|
+
})
|
|
207
|
+
).account
|
|
208
|
+
|
|
209
|
+
const publicClient = getPublicClient(anvilRpc)
|
|
210
|
+
|
|
211
|
+
const pimlicoClient = createPimlicoClient({
|
|
212
|
+
transport: http(rpc.paymasterRpc),
|
|
213
|
+
entryPoint: {
|
|
214
|
+
address: entryPoint07Address,
|
|
215
|
+
version: "0.7"
|
|
216
|
+
}
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
const smartAccountClient = createSmartAccountClient({
|
|
220
|
+
// @ts-ignore
|
|
221
|
+
client: getPublicClient(anvilRpc),
|
|
222
|
+
account,
|
|
223
|
+
paymaster: pimlicoClient,
|
|
224
|
+
chain: foundry,
|
|
225
|
+
userOperation: {
|
|
226
|
+
prepareUserOperation:
|
|
227
|
+
prepareUserOperationForErc20Paymaster(
|
|
228
|
+
pimlicoClient,
|
|
229
|
+
{
|
|
230
|
+
balanceOverride: true
|
|
231
|
+
}
|
|
232
|
+
)
|
|
233
|
+
},
|
|
234
|
+
bundlerTransport: http(rpc.altoRpc)
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
const INITIAL_TOKEN_BALANCE = parseEther("100")
|
|
238
|
+
const INTIAL_ETH_BALANCE = await publicClient.getBalance({
|
|
239
|
+
address: smartAccountClient.account.address
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
sudoMintTokens({
|
|
243
|
+
amount: INITIAL_TOKEN_BALANCE,
|
|
244
|
+
to: smartAccountClient.account.address,
|
|
245
|
+
anvilRpc
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
const opHash = await smartAccountClient.sendUserOperation({
|
|
249
|
+
calls: [
|
|
250
|
+
{
|
|
251
|
+
to: zeroAddress,
|
|
252
|
+
data: "0x",
|
|
253
|
+
value: 0n
|
|
254
|
+
}
|
|
255
|
+
],
|
|
256
|
+
paymasterContext: {
|
|
257
|
+
token: ERC20_ADDRESS
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
const receipt =
|
|
262
|
+
await smartAccountClient.waitForUserOperationReceipt({
|
|
263
|
+
hash: opHash
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
expect(receipt).toBeTruthy()
|
|
267
|
+
expect(receipt).toBeTruthy()
|
|
268
|
+
expect(receipt.success).toBeTruthy()
|
|
269
|
+
|
|
270
|
+
const FINAL_TOKEN_BALANCE = await tokenBalanceOf(
|
|
271
|
+
smartAccountClient.account.address,
|
|
272
|
+
rpc.anvilRpc
|
|
273
|
+
)
|
|
274
|
+
const FINAL_ETH_BALANCE = await publicClient.getBalance({
|
|
275
|
+
address: smartAccountClient.account.address
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
expect(FINAL_TOKEN_BALANCE).toBeLessThan(INITIAL_TOKEN_BALANCE) // Token balance should be deducted
|
|
279
|
+
expect(FINAL_ETH_BALANCE).toEqual(INTIAL_ETH_BALANCE) // There should be no ETH balance change
|
|
280
|
+
}
|
|
281
|
+
)
|
|
194
282
|
}
|
|
195
283
|
)
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
type Chain,
|
|
4
4
|
type Client,
|
|
5
5
|
type ContractFunctionParameters,
|
|
6
|
+
RpcError,
|
|
6
7
|
type Transport,
|
|
7
8
|
encodeFunctionData,
|
|
8
9
|
erc20Abi,
|
|
@@ -24,9 +25,21 @@ import { getChainId as getChainId_ } from "viem/actions"
|
|
|
24
25
|
import { readContract } from "viem/actions"
|
|
25
26
|
import { getAction, parseAccount } from "viem/utils"
|
|
26
27
|
import { getTokenQuotes } from "../../../actions/pimlico"
|
|
28
|
+
import { erc20AllowanceOverride, erc20BalanceOverride } from "../../../utils"
|
|
27
29
|
|
|
28
30
|
export const prepareUserOperationForErc20Paymaster =
|
|
29
|
-
(
|
|
31
|
+
(
|
|
32
|
+
pimlicoClient: Client,
|
|
33
|
+
{
|
|
34
|
+
balanceOverride = false,
|
|
35
|
+
balanceSlot: _balanceSlot,
|
|
36
|
+
allowanceSlot: _allowanceSlot
|
|
37
|
+
}: {
|
|
38
|
+
balanceOverride?: boolean
|
|
39
|
+
balanceSlot?: bigint
|
|
40
|
+
allowanceSlot?: bigint
|
|
41
|
+
} = {}
|
|
42
|
+
) =>
|
|
30
43
|
async <
|
|
31
44
|
account extends SmartAccount | undefined,
|
|
32
45
|
const calls extends readonly unknown[],
|
|
@@ -95,6 +108,13 @@ export const prepareUserOperationForErc20Paymaster =
|
|
|
95
108
|
entryPointAddress: account.entryPoint.address
|
|
96
109
|
})
|
|
97
110
|
|
|
111
|
+
if (quotes.length === 0) {
|
|
112
|
+
throw new RpcError(new Error("Quotes not found"), {
|
|
113
|
+
shortMessage:
|
|
114
|
+
"client didn't return token quotes, check if the token is supported"
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
|
|
98
118
|
const {
|
|
99
119
|
postOpGas,
|
|
100
120
|
exchangeRate,
|
|
@@ -118,9 +138,55 @@ export const prepareUserOperationForErc20Paymaster =
|
|
|
118
138
|
}
|
|
119
139
|
|
|
120
140
|
////////////////////////////////////////////////////////////////////////////////
|
|
141
|
+
|
|
121
142
|
// Call prepareUserOperation
|
|
122
143
|
////////////////////////////////////////////////////////////////////////////////
|
|
123
144
|
|
|
145
|
+
const allowanceSlot = _allowanceSlot ?? quotes[0].allowanceSlot
|
|
146
|
+
const balanceSlot = _balanceSlot ?? quotes[0].balanceSlot
|
|
147
|
+
|
|
148
|
+
const hasSlot = allowanceSlot && balanceSlot
|
|
149
|
+
|
|
150
|
+
if (!hasSlot && balanceOverride) {
|
|
151
|
+
throw new Error(
|
|
152
|
+
`balanceOverride is not supported for token ${token}, provide custom slot for balance & allowance overrides`
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const balanceStateOverride =
|
|
157
|
+
balanceOverride && balanceSlot
|
|
158
|
+
? erc20BalanceOverride({
|
|
159
|
+
token,
|
|
160
|
+
owner: account.address,
|
|
161
|
+
slot: balanceSlot
|
|
162
|
+
})[0]
|
|
163
|
+
: undefined
|
|
164
|
+
|
|
165
|
+
const allowanceStateOverride =
|
|
166
|
+
balanceOverride && allowanceSlot
|
|
167
|
+
? erc20AllowanceOverride({
|
|
168
|
+
token,
|
|
169
|
+
owner: account.address,
|
|
170
|
+
spender: paymasterERC20Address,
|
|
171
|
+
slot: allowanceSlot
|
|
172
|
+
})[0]
|
|
173
|
+
: undefined
|
|
174
|
+
|
|
175
|
+
parameters.stateOverride =
|
|
176
|
+
balanceOverride &&
|
|
177
|
+
balanceStateOverride &&
|
|
178
|
+
allowanceStateOverride // allowanceSlot && balanceSlot is cuz of TypeScript :/
|
|
179
|
+
? (parameters.stateOverride ?? []).concat([
|
|
180
|
+
{
|
|
181
|
+
address: token,
|
|
182
|
+
stateDiff: [
|
|
183
|
+
...(allowanceStateOverride.stateDiff ?? []),
|
|
184
|
+
...(balanceStateOverride.stateDiff ?? [])
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
])
|
|
188
|
+
: parameters.stateOverride
|
|
189
|
+
|
|
124
190
|
const userOperation = await getAction(
|
|
125
191
|
client,
|
|
126
192
|
prepareUserOperation,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "permissionless",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.11",
|
|
4
4
|
"author": "Pimlico",
|
|
5
5
|
"homepage": "https://docs.pimlico.io/permissionless",
|
|
6
6
|
"repository": "github:pimlicolabs/permissionless.js",
|
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
"type": "module",
|
|
12
12
|
"sideEffects": false,
|
|
13
13
|
"description": "A utility library for working with ERC-4337",
|
|
14
|
-
"keywords": [
|
|
14
|
+
"keywords": [
|
|
15
|
+
"ethereum",
|
|
16
|
+
"erc-4337",
|
|
17
|
+
"eip-4337",
|
|
18
|
+
"paymaster",
|
|
19
|
+
"bundler"
|
|
20
|
+
],
|
|
15
21
|
"license": "MIT",
|
|
16
22
|
"exports": {
|
|
17
23
|
".": {
|
|
@@ -71,6 +77,6 @@
|
|
|
71
77
|
}
|
|
72
78
|
},
|
|
73
79
|
"peerDependencies": {
|
|
74
|
-
"viem": "^2.21.
|
|
80
|
+
"viem": "^2.21.22"
|
|
75
81
|
}
|
|
76
82
|
}
|
package/types/pimlico.ts
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { toHex } from "viem"
|
|
2
|
+
import { describe, expect, test } from "vitest"
|
|
3
|
+
import {
|
|
4
|
+
type Erc20AllowanceOverrideParameters,
|
|
5
|
+
erc20AllowanceOverride
|
|
6
|
+
} from "./erc20AllowanceOverride"
|
|
7
|
+
|
|
8
|
+
describe("erc20AllowanceOverride", () => {
|
|
9
|
+
test("should return the correct structure for valid inputs", () => {
|
|
10
|
+
const params = {
|
|
11
|
+
token: "0xTokenAddress",
|
|
12
|
+
owner: "0xOwnerAddress",
|
|
13
|
+
spender: "0xSpenderAddress",
|
|
14
|
+
slot: BigInt(1),
|
|
15
|
+
amount: BigInt(100)
|
|
16
|
+
} as const
|
|
17
|
+
|
|
18
|
+
const result = erc20AllowanceOverride(params)
|
|
19
|
+
|
|
20
|
+
expect(result).toEqual([
|
|
21
|
+
{
|
|
22
|
+
address: params.token,
|
|
23
|
+
stateDiff: [
|
|
24
|
+
{
|
|
25
|
+
slot: expect.any(String), // Slot will be a keccak256 hash
|
|
26
|
+
value: toHex(params.amount)
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
])
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test("should use the default amount when none is provided", () => {
|
|
34
|
+
const params: Erc20AllowanceOverrideParameters = {
|
|
35
|
+
token: "0xTokenAddress",
|
|
36
|
+
owner: "0xOwnerAddress",
|
|
37
|
+
spender: "0xSpenderAddress",
|
|
38
|
+
slot: BigInt(1)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const result = erc20AllowanceOverride(params)
|
|
42
|
+
|
|
43
|
+
const expectedDefaultAmount = BigInt(
|
|
44
|
+
"0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
expect(result).toEqual([
|
|
48
|
+
{
|
|
49
|
+
address: params.token,
|
|
50
|
+
stateDiff: [
|
|
51
|
+
{
|
|
52
|
+
slot: expect.any(String), // Slot will be a keccak256 hash
|
|
53
|
+
value: toHex(expectedDefaultAmount)
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
])
|
|
58
|
+
})
|
|
59
|
+
})
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Address,
|
|
3
|
+
type StateOverride,
|
|
4
|
+
encodeAbiParameters,
|
|
5
|
+
keccak256,
|
|
6
|
+
toHex
|
|
7
|
+
} from "viem"
|
|
8
|
+
|
|
9
|
+
export type Erc20AllowanceOverrideParameters = {
|
|
10
|
+
token: Address
|
|
11
|
+
owner: Address
|
|
12
|
+
spender: Address
|
|
13
|
+
slot: bigint
|
|
14
|
+
amount?: bigint
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function erc20AllowanceOverride({
|
|
18
|
+
token,
|
|
19
|
+
owner,
|
|
20
|
+
spender,
|
|
21
|
+
slot,
|
|
22
|
+
amount = BigInt(
|
|
23
|
+
"0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
|
24
|
+
)
|
|
25
|
+
}: Erc20AllowanceOverrideParameters): StateOverride {
|
|
26
|
+
const smartAccountErc20AllowanceSlot = keccak256(
|
|
27
|
+
encodeAbiParameters(
|
|
28
|
+
[
|
|
29
|
+
{
|
|
30
|
+
type: "address"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: "bytes32"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
spender,
|
|
38
|
+
keccak256(
|
|
39
|
+
encodeAbiParameters(
|
|
40
|
+
[
|
|
41
|
+
{
|
|
42
|
+
type: "address"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: "uint256"
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
[owner, BigInt(slot)]
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
]
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
return [
|
|
56
|
+
{
|
|
57
|
+
address: token,
|
|
58
|
+
stateDiff: [
|
|
59
|
+
{
|
|
60
|
+
slot: smartAccountErc20AllowanceSlot,
|
|
61
|
+
value: toHex(amount)
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { toHex } from "viem"
|
|
2
|
+
import { describe, expect, test } from "vitest"
|
|
3
|
+
import {
|
|
4
|
+
type Erc20BalanceOverrideParameters,
|
|
5
|
+
erc20BalanceOverride
|
|
6
|
+
} from "./erc20BalanceOverride"
|
|
7
|
+
|
|
8
|
+
describe("erc20BalanceOverride", () => {
|
|
9
|
+
test("should return the correct structure for valid inputs", () => {
|
|
10
|
+
const params = {
|
|
11
|
+
token: "0xTokenAddress",
|
|
12
|
+
owner: "0xOwnerAddress",
|
|
13
|
+
slot: BigInt(1),
|
|
14
|
+
balance: BigInt(1000)
|
|
15
|
+
} as const
|
|
16
|
+
|
|
17
|
+
const result = erc20BalanceOverride(params)
|
|
18
|
+
|
|
19
|
+
expect(result).toEqual([
|
|
20
|
+
{
|
|
21
|
+
address: params.token,
|
|
22
|
+
stateDiff: [
|
|
23
|
+
{
|
|
24
|
+
slot: expect.any(String), // Slot will be a keccak256 hash
|
|
25
|
+
value: toHex(params.balance)
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
])
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test("should use the default balance when none is provided", () => {
|
|
33
|
+
const params: Erc20BalanceOverrideParameters = {
|
|
34
|
+
token: "0xTokenAddress",
|
|
35
|
+
owner: "0xOwnerAddress",
|
|
36
|
+
slot: BigInt(1)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const result = erc20BalanceOverride(params)
|
|
40
|
+
|
|
41
|
+
const expectedDefaultBalance = BigInt(
|
|
42
|
+
"0x100000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
expect(result).toEqual([
|
|
46
|
+
{
|
|
47
|
+
address: params.token,
|
|
48
|
+
stateDiff: [
|
|
49
|
+
{
|
|
50
|
+
slot: expect.any(String), // Slot will be a keccak256 hash
|
|
51
|
+
value: toHex(expectedDefaultBalance)
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
])
|
|
56
|
+
})
|
|
57
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Address,
|
|
3
|
+
type StateOverride,
|
|
4
|
+
encodeAbiParameters,
|
|
5
|
+
keccak256,
|
|
6
|
+
toHex
|
|
7
|
+
} from "viem"
|
|
8
|
+
|
|
9
|
+
export type Erc20BalanceOverrideParameters = {
|
|
10
|
+
token: Address
|
|
11
|
+
owner: Address
|
|
12
|
+
slot: bigint
|
|
13
|
+
balance?: bigint
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function erc20BalanceOverride({
|
|
17
|
+
token,
|
|
18
|
+
owner,
|
|
19
|
+
slot,
|
|
20
|
+
balance = BigInt(
|
|
21
|
+
"0x100000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
|
22
|
+
)
|
|
23
|
+
}: Erc20BalanceOverrideParameters): StateOverride {
|
|
24
|
+
const smartAccountErc20BalanceSlot = keccak256(
|
|
25
|
+
encodeAbiParameters(
|
|
26
|
+
[
|
|
27
|
+
{
|
|
28
|
+
type: "address"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
type: "uint256"
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
[owner, slot]
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
return [
|
|
39
|
+
{
|
|
40
|
+
address: token,
|
|
41
|
+
stateDiff: [
|
|
42
|
+
{
|
|
43
|
+
slot: smartAccountErc20BalanceSlot,
|
|
44
|
+
value: toHex(balance)
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
package/utils/index.ts
CHANGED
|
@@ -17,6 +17,14 @@ import {
|
|
|
17
17
|
import { getPackedUserOperation } from "./getPackedUserOperation"
|
|
18
18
|
|
|
19
19
|
import { type EncodeCallDataParams, encode7579Calls } from "./encode7579Calls"
|
|
20
|
+
import {
|
|
21
|
+
type Erc20AllowanceOverrideParameters,
|
|
22
|
+
erc20AllowanceOverride
|
|
23
|
+
} from "./erc20AllowanceOverride"
|
|
24
|
+
import {
|
|
25
|
+
type Erc20BalanceOverrideParameters,
|
|
26
|
+
erc20BalanceOverride
|
|
27
|
+
} from "./erc20BalanceOverride"
|
|
20
28
|
|
|
21
29
|
export {
|
|
22
30
|
transactionReceiptStatus,
|
|
@@ -32,5 +40,9 @@ export {
|
|
|
32
40
|
type EncodeInstallModuleParameters,
|
|
33
41
|
encodeInstallModule,
|
|
34
42
|
type EncodeCallDataParams,
|
|
35
|
-
encode7579Calls
|
|
43
|
+
encode7579Calls,
|
|
44
|
+
erc20AllowanceOverride,
|
|
45
|
+
erc20BalanceOverride,
|
|
46
|
+
type Erc20AllowanceOverrideParameters,
|
|
47
|
+
type Erc20BalanceOverrideParameters
|
|
36
48
|
}
|