-
Notifications
You must be signed in to change notification settings - Fork 327
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cbd8060
commit 5b86081
Showing
7 changed files
with
123 additions
and
120 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
150 changes: 80 additions & 70 deletions
150
advanced/wallets/react-wallet-v2/src/lib/smart-accounts/builders/SafeUserOpBuilder.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,80 +1,90 @@ | ||
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; | ||
import { FillUserOpParams, FillUserOpResponse, SendUserOpWithSigantureParams, SendUserOpWithSigantureResponse, UserOpBuilder } from "./UserOpBuilder"; | ||
import { createPublicClient, http } from "viem"; | ||
import { signerToSafeSmartAccount } from "permissionless/accounts"; | ||
import { createSmartAccountClient, ENTRYPOINT_ADDRESS_V07, getUserOperationHash } from "permissionless"; | ||
import { createPimlicoBundlerClient, createPimlicoPaymasterClient } from "permissionless/clients/pimlico"; | ||
import { bundlerUrl, paymasterUrl, publicClientUrl } from "@/utils/SmartAccountUtil"; | ||
|
||
import { getChainById } from "@/utils/ChainUtil"; | ||
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts' | ||
import { | ||
FillUserOpParams, | ||
FillUserOpResponse, | ||
SendUserOpWithSigantureParams, | ||
SendUserOpWithSigantureResponse, | ||
UserOpBuilder | ||
} from './UserOpBuilder' | ||
import { createPublicClient, http } from 'viem' | ||
import { signerToSafeSmartAccount } from 'permissionless/accounts' | ||
import { | ||
createSmartAccountClient, | ||
ENTRYPOINT_ADDRESS_V07, | ||
getUserOperationHash | ||
} from 'permissionless' | ||
import { | ||
createPimlicoBundlerClient, | ||
createPimlicoPaymasterClient | ||
} from 'permissionless/clients/pimlico' | ||
import { bundlerUrl, paymasterUrl, publicClientUrl } from '@/utils/SmartAccountUtil' | ||
|
||
import { getChainById } from '@/utils/ChainUtil' | ||
|
||
const PIMLICO_API_KEY = process.env['NEXT_PUBLIC_PIMLICO_KEY'] | ||
|
||
export class SafeUserOpBuilder implements UserOpBuilder { | ||
async fillUserOp(params: FillUserOpParams): Promise<FillUserOpResponse> { | ||
const privateKey = generatePrivateKey() | ||
const signer = privateKeyToAccount(privateKey) | ||
const chain = getChainById(params.chainId) | ||
|
||
const publicClient = createPublicClient({ | ||
transport: http(publicClientUrl({ chain })) | ||
}) | ||
|
||
async fillUserOp(params: FillUserOpParams): Promise<FillUserOpResponse> { | ||
|
||
const privateKey = generatePrivateKey() | ||
const signer = privateKeyToAccount(privateKey) | ||
const chain = getChainById(params.chainId) | ||
|
||
const publicClient = createPublicClient({ | ||
transport: http(publicClientUrl({ chain })) | ||
}) | ||
const paymasterClient = createPimlicoPaymasterClient({ | ||
transport: http(paymasterUrl({ chain }), { | ||
timeout: 30000 | ||
}), | ||
entryPoint: ENTRYPOINT_ADDRESS_V07 | ||
}) | ||
|
||
const paymasterClient = createPimlicoPaymasterClient({ | ||
transport: http(paymasterUrl({ chain }), { | ||
timeout: 30000 | ||
}), | ||
entryPoint: ENTRYPOINT_ADDRESS_V07, | ||
}) | ||
const bundlerTransport = http(bundlerUrl({ chain }), { | ||
timeout: 30000 | ||
}) | ||
const pimlicoBundlerClient = createPimlicoBundlerClient({ | ||
transport: bundlerTransport, | ||
entryPoint: ENTRYPOINT_ADDRESS_V07 | ||
}) | ||
|
||
const bundlerTransport = http(bundlerUrl({ chain }), { | ||
timeout: 30000 | ||
}) | ||
const pimlicoBundlerClient = createPimlicoBundlerClient({ | ||
transport: bundlerTransport, | ||
entryPoint: ENTRYPOINT_ADDRESS_V07, | ||
}) | ||
|
||
const safeAccount = await signerToSafeSmartAccount(publicClient, { | ||
entryPoint: ENTRYPOINT_ADDRESS_V07, | ||
signer: signer, | ||
safeVersion: "1.4.1", | ||
address: params.account | ||
}) | ||
|
||
const smartAccountClient = createSmartAccountClient({ | ||
account: safeAccount, | ||
entryPoint: ENTRYPOINT_ADDRESS_V07, | ||
chain, | ||
bundlerTransport, | ||
middleware: { | ||
sponsorUserOperation: paymasterClient.sponsorUserOperation, // optional | ||
gasPrice: async () => (await pimlicoBundlerClient.getUserOperationGasPrice()).fast, // if using pimlico bundler | ||
}, | ||
}) | ||
const account = smartAccountClient.account | ||
const userOp = await smartAccountClient.prepareUserOperationRequest({ | ||
userOperation: { | ||
callData: await account.encodeCallData(params.calls) | ||
}, | ||
account: account | ||
}) | ||
const hash = getUserOperationHash({ | ||
userOperation: userOp, | ||
chainId: chain.id, | ||
entryPoint: ENTRYPOINT_ADDRESS_V07 | ||
}) | ||
return { | ||
userOp, | ||
hash | ||
} | ||
} | ||
sendUserOpWithSignature(params: SendUserOpWithSigantureParams): Promise<SendUserOpWithSigantureResponse> { | ||
throw new Error("Method not implemented."); | ||
} | ||
const safeAccount = await signerToSafeSmartAccount(publicClient, { | ||
entryPoint: ENTRYPOINT_ADDRESS_V07, | ||
signer: signer, | ||
safeVersion: '1.4.1', | ||
address: params.account | ||
}) | ||
|
||
} | ||
const smartAccountClient = createSmartAccountClient({ | ||
account: safeAccount, | ||
entryPoint: ENTRYPOINT_ADDRESS_V07, | ||
chain, | ||
bundlerTransport, | ||
middleware: { | ||
sponsorUserOperation: paymasterClient.sponsorUserOperation, // optional | ||
gasPrice: async () => (await pimlicoBundlerClient.getUserOperationGasPrice()).fast // if using pimlico bundler | ||
} | ||
}) | ||
const account = smartAccountClient.account | ||
const userOp = await smartAccountClient.prepareUserOperationRequest({ | ||
userOperation: { | ||
callData: await account.encodeCallData(params.calls) | ||
}, | ||
account: account | ||
}) | ||
const hash = getUserOperationHash({ | ||
userOperation: userOp, | ||
chainId: chain.id, | ||
entryPoint: ENTRYPOINT_ADDRESS_V07 | ||
}) | ||
return { | ||
userOp, | ||
hash | ||
} | ||
} | ||
sendUserOpWithSignature( | ||
params: SendUserOpWithSigantureParams | ||
): Promise<SendUserOpWithSigantureResponse> { | ||
throw new Error('Method not implemented.') | ||
} | ||
} |
41 changes: 21 additions & 20 deletions
41
advanced/wallets/react-wallet-v2/src/lib/smart-accounts/builders/UserOpBuilder.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,36 @@ | ||
import { UserOperation } from "permissionless"; | ||
import { Address, Hex } from "viem"; | ||
import { UserOperation } from 'permissionless' | ||
import { Address, Hex } from 'viem' | ||
|
||
type Call = { to: Address; value: bigint; data: Hex } | ||
|
||
type UserOp = UserOperation<"v0.7"> | ||
type UserOp = UserOperation<'v0.7'> | ||
|
||
export type FillUserOpParams = { | ||
chainId: number; | ||
account: Address; | ||
calls: Call[]; | ||
capabilities: { | ||
paymasterService?: { url: string }; | ||
permissions?: { context: Hex }; | ||
}; | ||
chainId: number | ||
account: Address | ||
calls: Call[] | ||
capabilities: { | ||
paymasterService?: { url: string } | ||
permissions?: { context: Hex } | ||
} | ||
} | ||
export type FillUserOpResponse = { | ||
userOp: UserOp | ||
hash: Hex | ||
} | ||
} | ||
export type SendUserOpWithSigantureParams = { | ||
chainId: Hex; | ||
userOp: UserOp; | ||
signature: Hex; | ||
permissionsContext?: Hex; | ||
chainId: Hex | ||
userOp: UserOp | ||
signature: Hex | ||
permissionsContext?: Hex | ||
} | ||
export type SendUserOpWithSigantureResponse = { | ||
receipt: Hex | ||
receipt: Hex | ||
} | ||
|
||
|
||
export interface UserOpBuilder { | ||
fillUserOp(params: FillUserOpParams): Promise<FillUserOpResponse> | ||
sendUserOpWithSignature(params: SendUserOpWithSigantureParams): Promise<SendUserOpWithSigantureResponse> | ||
} | ||
fillUserOp(params: FillUserOpParams): Promise<FillUserOpResponse> | ||
sendUserOpWithSignature( | ||
params: SendUserOpWithSigantureParams | ||
): Promise<SendUserOpWithSigantureResponse> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,12 @@ | ||
import { SafeUserOpBuilder } from "@/lib/smart-accounts/builders/SafeUserOpBuilder"; | ||
import { FillUserOpResponse } from "@/lib/smart-accounts/builders/UserOpBuilder"; | ||
import { NextApiRequest, NextApiResponse } from "next"; | ||
import { SafeUserOpBuilder } from '@/lib/smart-accounts/builders/SafeUserOpBuilder' | ||
import { FillUserOpResponse } from '@/lib/smart-accounts/builders/UserOpBuilder' | ||
import { NextApiRequest, NextApiResponse } from 'next' | ||
|
||
|
||
export default async function handler( | ||
req: NextApiRequest, | ||
res: NextApiResponse<FillUserOpResponse> | ||
) { | ||
const builder = new SafeUserOpBuilder() | ||
const response = await builder.fillUserOp(req.body) | ||
res.status(200).json(response) | ||
} | ||
req: NextApiRequest, | ||
res: NextApiResponse<FillUserOpResponse> | ||
) { | ||
const builder = new SafeUserOpBuilder() | ||
const response = await builder.fillUserOp(req.body) | ||
res.status(200).json(response) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,12 @@ | ||
import * as chains from "viem/chains"; | ||
import { Chain } from "viem/chains"; | ||
|
||
import * as chains from 'viem/chains' | ||
import { Chain } from 'viem/chains' | ||
|
||
export function getChainById(chainId: number): Chain { | ||
for (const chain of Object.values(chains)) { | ||
if (chain.id === chainId) { | ||
return chain; | ||
} | ||
for (const chain of Object.values(chains)) { | ||
if (chain.id === chainId) { | ||
return chain | ||
} | ||
|
||
throw new Error(`Chain with id ${chainId} not found`); | ||
} | ||
} | ||
|
||
throw new Error(`Chain with id ${chainId} not found`) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -212,4 +212,3 @@ export function bigIntReplacer(_key: string, value: any) { | |
|
||
return value | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters