diff --git a/examples/cli.ts b/examples/cli.ts index 51726fa..2fd78be 100644 --- a/examples/cli.ts +++ b/examples/cli.ts @@ -28,16 +28,14 @@ export async function loadEnv(): Promise { export async function loadArgs(): Promise { return yargs(hideBin(process.argv)) - .option("usePaymaster", { - type: "boolean", + .option("sponsorshipPolicy", { + type: "string", description: "Have transaction sponsored by paymaster service", - default: false, }) .option("recoveryAddress", { type: "string", description: "Recovery address to be attached as owner of the Safe (immediately adter deployment)", - default: undefined, }) .option("safeSaltNonce", { type: "string", diff --git a/examples/send-tx.ts b/examples/send-tx.ts index 336b7bd..b7f31f2 100644 --- a/examples/send-tx.ts +++ b/examples/send-tx.ts @@ -10,7 +10,7 @@ dotenv.config(); async function main(): Promise { const [ { pimlicoKey, nearAccountId, nearAccountPrivateKey }, - { mpcContractId, recoveryAddress, usePaymaster }, + { mpcContractId, recoveryAddress, sponsorshipPolicy }, ] = await Promise.all([loadEnv(), loadArgs()]); const chainId = 11155111; const txManager = await NearSafe.create({ @@ -44,7 +44,7 @@ async function main(): Promise { const unsignedUserOp = await txManager.buildTransaction({ chainId, transactions, - usePaymaster, + sponsorshipPolicy, }); console.log("Unsigned UserOp", unsignedUserOp); const safeOpHash = await txManager.opHash(chainId, unsignedUserOp); @@ -56,7 +56,7 @@ async function main(): Promise { const sufficientFunded = await txManager.sufficientlyFunded( chainId, transactions, - usePaymaster ? 0n : gasCost + !!sponsorshipPolicy ? 0n : gasCost ); if (!sufficientFunded) { console.warn( diff --git a/src/lib/bundler.ts b/src/lib/bundler.ts index faaa0f3..dd7031e 100644 --- a/src/lib/bundler.ts +++ b/src/lib/bundler.ts @@ -24,10 +24,14 @@ function bundlerUrl(chainId: number, apikey: string): string { return `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${apikey}`; } +type SponsorshipPolicy = { sponsorshipPolicyId: string }; + type BundlerRpcSchema = [ { Method: "pm_sponsorUserOperation"; - Parameters: [UnsignedUserOperation, Address]; + // TODO(bh2smith): Add possiblity to not supply policy: + // [UnsignedUserOperation, Address] + Parameters: [UnsignedUserOperation, Address, SponsorshipPolicy]; ReturnType: PaymasterData; }, { @@ -65,11 +69,11 @@ export class Erc4337Bundler { async getPaymasterData( rawUserOp: UnsignedUserOperation, - usePaymaster: boolean, - safeNotDeployed: boolean + safeNotDeployed: boolean, + sponsorshipPolicy?: string ): Promise { // TODO: Keep this option out of the bundler - if (usePaymaster) { + if (sponsorshipPolicy) { console.log("Requesting paymaster data..."); return handleRequest(() => this.client.request({ @@ -77,6 +81,7 @@ export class Erc4337Bundler { params: [ { ...rawUserOp, signature: PLACEHOLDER_SIG }, this.entryPointAddress, + { sponsorshipPolicyId: sponsorshipPolicy }, ], }) ); diff --git a/src/near-safe.ts b/src/near-safe.ts index 4418a67..1692541 100644 --- a/src/near-safe.ts +++ b/src/near-safe.ts @@ -158,9 +158,9 @@ export class NearSafe { async buildTransaction(args: { chainId: number; transactions: MetaTransaction[]; - usePaymaster: boolean; + sponsorshipPolicy?: string; }): Promise { - const { transactions, usePaymaster, chainId } = args; + const { transactions, sponsorshipPolicy, chainId } = args; if (transactions.length === 0) { throw new Error("Empty transaction set!"); } @@ -189,8 +189,8 @@ export class NearSafe { const paymasterData = await bundler.getPaymasterData( rawUserOp, - usePaymaster, - !safeDeployed + !safeDeployed, + sponsorshipPolicy ); const unsignedUserOp = { ...rawUserOp, ...paymasterData }; @@ -228,11 +228,11 @@ export class NearSafe { */ async encodeSignRequest( signRequest: SignRequestData, - usePaymaster: boolean + sponsorshipPolicy?: string ): Promise { const { payload, evmMessage, hash } = await this.requestRouter( signRequest, - usePaymaster + sponsorshipPolicy ); return { nearPayload: await this.nearAdapter.mpcContract.encodeSignatureRequestTx({ @@ -420,7 +420,7 @@ export class NearSafe { */ async requestRouter( { method, chainId, params }: SignRequestData, - usePaymaster: boolean + sponsorshipPolicy?: string ): Promise<{ evmMessage: string; payload: number[]; @@ -460,7 +460,7 @@ export class NearSafe { const userOp = await this.buildTransaction({ chainId, transactions, - usePaymaster, + ...(sponsorshipPolicy ? { sponsorshipPolicy } : {}), }); const opHash = await this.opHash(chainId, userOp); return { diff --git a/src/types.ts b/src/types.ts index 09d009c..455c110 100644 --- a/src/types.ts +++ b/src/types.ts @@ -86,7 +86,7 @@ export interface PaymasterData { */ export interface UserOptions { /** Whether to use a paymaster for gas fee coverage. */ - usePaymaster: boolean; + sponsorshipPolicy?: string; /** The unique nonce used to differentiate multiple Safe setups. */ safeSaltNonce: string; /** The NEAR contract ID for the MPC contract. */