Skip to content

Commit

Permalink
Add balanceOverride in prepareUserOperationForErc20Paymaster
Browse files Browse the repository at this point in the history
  • Loading branch information
plusminushalf committed Oct 22, 2024
1 parent fc63277 commit 08f2e76
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/long-walls-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"permissionless": patch
---

Added utils to create erc20 state overrides
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"get-port": "^7.0.0",
"tsc-alias": "^1.8.8",
"vitest": "^1.2.0",
"viem": "^2.21.2",
"viem": "2.21.22",
"wagmi": "^2.12.8",
"@permissionless/wagmi": "workspace:packages/wagmi",
"@types/react": "^18.3.1",
Expand Down
4 changes: 4 additions & 0 deletions packages/permissionless/actions/pimlico/getTokenQuotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export type GetTokenQuotesReturnType = {
postOpGas: bigint
exchangeRate: bigint
exchangeRateNativeToUsd: bigint
balanceSlot: bigint
approvalSlot: bigint
}[]

/**
Expand Down Expand Up @@ -62,6 +64,8 @@ export const getTokenQuotes = async <

return res.quotes.map((quote) => ({
...quote,
balanceSlot: hexToBigInt(quote.balanceSlot),
approvalSlot: hexToBigInt(quote.approvalSlot),
postOpGas: hexToBigInt(quote.postOpGas),
exchangeRate: hexToBigInt(quote.exchangeRate),
exchangeRateNativeToUsd: hexToBigInt(quote.exchangeRateNativeToUsd)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,5 +191,93 @@ describe.each(getCoreSmartAccounts())(
expect(FINAL_ETH_BALANCE).toEqual(INTIAL_ETH_BALANCE) // There should be no ETH balance change
}
)

testWithRpc.skipIf(!supportsEntryPointV07)(
"prepareUserOperationForErc20Paymaster_v07",
async ({ rpc }) => {
const { anvilRpc } = rpc

const account = (
await getSmartAccountClient({
entryPoint: {
version: "0.7"
},
...rpc
})
).account

const publicClient = getPublicClient(anvilRpc)

const pimlicoClient = createPimlicoClient({
transport: http(rpc.paymasterRpc),
entryPoint: {
address: entryPoint07Address,
version: "0.7"
}
})

const smartAccountClient = createSmartAccountClient({
// @ts-ignore
client: getPublicClient(anvilRpc),
account,
paymaster: pimlicoClient,
chain: foundry,
userOperation: {
prepareUserOperation:
prepareUserOperationForErc20Paymaster(
pimlicoClient,
{
balanceOverride: true
}
)
},
bundlerTransport: http(rpc.altoRpc)
})

const INITIAL_TOKEN_BALANCE = parseEther("100")
const INTIAL_ETH_BALANCE = await publicClient.getBalance({
address: smartAccountClient.account.address
})

sudoMintTokens({
amount: INITIAL_TOKEN_BALANCE,
to: smartAccountClient.account.address,
anvilRpc
})

const opHash = await smartAccountClient.sendUserOperation({
calls: [
{
to: zeroAddress,
data: "0x",
value: 0n
}
],
paymasterContext: {
token: ERC20_ADDRESS
}
})

const receipt =
await smartAccountClient.waitForUserOperationReceipt({
hash: opHash
})

expect(receipt).toBeTruthy()
expect(receipt).toBeTruthy()
expect(receipt.success).toBeTruthy()

const FINAL_TOKEN_BALANCE = await tokenBalanceOf(
smartAccountClient.account.address,
rpc.anvilRpc
)
const FINAL_ETH_BALANCE = await publicClient.getBalance({
address: smartAccountClient.account.address
})

expect(FINAL_TOKEN_BALANCE).toBeLessThan(INITIAL_TOKEN_BALANCE) // Token balance should be deducted
expect(FINAL_ETH_BALANCE).toEqual(INTIAL_ETH_BALANCE) // There should be no ETH balance change
}
)
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,17 @@ import { getChainId as getChainId_ } from "viem/actions"
import { readContract } from "viem/actions"
import { getAction, parseAccount } from "viem/utils"
import { getTokenQuotes } from "../../../actions/pimlico"
import { erc20ApprovalOverride, erc20BalanceOverride } from "../../../utils"

export const prepareUserOperationForErc20Paymaster =
(pimlicoClient: Client) =>
(
pimlicoClient: Client,
{
balanceOverride = false
}: {
balanceOverride?: boolean
} = {}
) =>
async <
account extends SmartAccount | undefined,
const calls extends readonly unknown[],
Expand Down Expand Up @@ -98,6 +106,8 @@ export const prepareUserOperationForErc20Paymaster =
const {
postOpGas,
exchangeRate,
balanceSlot,
approvalSlot,
paymaster: paymasterERC20Address
} = quotes[0]

Expand All @@ -121,6 +131,22 @@ export const prepareUserOperationForErc20Paymaster =
// Call prepareUserOperation
////////////////////////////////////////////////////////////////////////////////

parameters.stateOverride = balanceOverride
? (parameters.stateOverride ?? []).concat(
erc20ApprovalOverride({
token,
owner: account.address,
spender: paymasterERC20Address,
slot: approvalSlot
}),
erc20BalanceOverride({
token,
owner: account.address,
slot: balanceSlot
})
)
: parameters.stateOverride

const userOperation = await getAction(
client,
prepareUserOperation,
Expand Down
2 changes: 1 addition & 1 deletion packages/permissionless/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,6 @@
}
},
"peerDependencies": {
"viem": "^2.21.2"
"viem": "^2.21.22"
}
}
2 changes: 2 additions & 0 deletions packages/permissionless/types/pimlico.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ type GetTokenQuotesWithBigIntAsHex = {
postOpGas: Hex
exchangeRate: Hex
exchangeRateNativeToUsd: Hex
balanceSlot: Hex
approvalSlot: Hex
}[]
}

Expand Down

0 comments on commit 08f2e76

Please sign in to comment.