Skip to content

Commit

Permalink
Update paymaster will sponsor
Browse files Browse the repository at this point in the history
  • Loading branch information
cpcramer committed Jun 11, 2024
1 parent 4a77853 commit 52c9547
Showing 1 changed file with 26 additions and 49 deletions.
75 changes: 26 additions & 49 deletions docs/pages/guides/paymasters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,68 +36,43 @@ for more on this.
The code below is built specifically for Smart Wallet. It would need to be updated to support other smart accounts.
:::code-group
```ts twoslash [utils.ts]
import { ENTRYPOINT_ADDRESS_V06, UserOperation } from "permissionless";
import {
Address,
BlockTag,
Hex,
decodeAbiParameters,
decodeFunctionData,
} from "viem";
import { UserOperation } from "permissionless";
import { Address, Hex, decodeFunctionData } from "viem";
import { baseSepolia } from "viem/chains";
import {client} from "./config"
import {
coinbaseSmartWalletABI,
coinbaseSmartWalletFactoryAddress,
coinbaseSmartWalletProxyBytecode,
coinbaseSmartWalletV1Implementation,
erc1967ProxyImplementationSlot,
magicSpendAddress
} from "./constants"
import { myNFTABI, myNFTAddress } from "./myNFT";
import { client } from "./config";
import { coinbaseSmartWalletABI, magicSpendAddress } from "./constants";
import { myNFTABI, myNFTAddress } from "@/ABIs/myNFT";
import { isValidAAEntrypoint } from "@coinbase/onchainkit/wallet";
import { isWalletASmartWallet } from "@coinbase/onchainkit/wallet";
import type { IsValidAAEntrypointOptions } from "@coinbase/onchainkit/wallet";
import type { IsWalletASmartWalletOptions } from "@coinbase/onchainkit/wallet";

// @noErrors
export async function willSponsor({
chainId,
entrypoint,
userOp,
}: { chainId: number; entrypoint: string; userOp: UserOperation<"v0.6"> }) {
}: {
chainId: number;
entrypoint: string;
userOp: UserOperation<"v0.6">;
}) {
// check chain id
if (chainId !== baseSepolia.id) return false;

// check entrypoint
// not strictly needed given below check on implementation address, but leaving as example
if (entrypoint.toLowerCase() !== ENTRYPOINT_ADDRESS_V06.toLowerCase())
if (!isValidAAEntrypoint({ entrypoint } as IsValidAAEntrypointOptions))
return false;

try {
// check the userOp.sender is a proxy with the expected bytecode
const code = await client.getBytecode({ address: userOp.sender });

if (!code) {
// no code at address, check that the initCode is deploying a Coinbase Smart Wallet
// factory address is first 20 bytes of initCode after '0x'
const factoryAddress = userOp.initCode.slice(0, 42);
if (factoryAddress.toLowerCase() !== coinbaseSmartWalletFactoryAddress.toLowerCase())
return false;
} else {
// code at address, check that it is a proxy to the expected implementation
if (code != coinbaseSmartWalletProxyBytecode) return false;

// check that userOp.sender proxies to expected implementation
const implementation = await client.request<{
Parameters: [Address, Hex, BlockTag];
ReturnType: Hex;
}>({
method: "eth_getStorageAt",
params: [userOp.sender, erc1967ProxyImplementationSlot, "latest"],
});
const implementationAddress = decodeAbiParameters(
[{ type: "address" }],
implementation
)[0];
if (implementationAddress != coinbaseSmartWalletV1Implementation)
return false;
}
// check the userOp.sender is a proxy with the expected bytecode and proxies to expected implementation
if (
!(await isWalletASmartWallet({
client,
userOp,
} as IsWalletASmartWalletOptions))
)
return false;

// check that userOp.callData is making a call we want to sponsor
const calldata = decodeFunctionData({
Expand All @@ -114,6 +89,7 @@ export async function willSponsor({
value: bigint;
data: Hex;
}[];

// modify if want to allow batch calls to your contract
if (calls.length > 2) return false;

Expand All @@ -135,6 +111,7 @@ export async function willSponsor({
abi: myNFTABI,
data: calls[callToCheckIndex].data,
});

if (innerCalldata.functionName !== "safeMint") return false;

return true;
Expand Down

0 comments on commit 52c9547

Please sign in to comment.