UNPKG

near-safe-test

Version:

An SDK for controlling Ethereum Smart Accounts via ERC4337 from a Near Account.

110 lines (109 loc) 4.27 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Erc4337Bundler = void 0; exports.stripApiKey = stripApiKey; const viem_1 = require("viem"); const util_1 = require("../util"); function bundlerUrl(chainId, apikey) { return `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${apikey}`; } class Erc4337Bundler { constructor(entryPointAddress, apiKey, chainId) { this.entryPointAddress = entryPointAddress; this.apiKey = apiKey; this.chainId = chainId; this.client = (0, viem_1.createPublicClient)({ transport: (0, viem_1.http)(bundlerUrl(chainId, this.apiKey)), rpcSchema: (0, viem_1.rpcSchema)(), }); } async getPaymasterData(rawUserOp, sponsorshipPolicy) { const userOp = { ...rawUserOp, signature: util_1.PLACEHOLDER_SIG }; if (sponsorshipPolicy) { console.log("Requesting paymaster data..."); return handleRequest(() => this.client.request({ method: "pm_sponsorUserOperation", params: [ userOp, this.entryPointAddress, { sponsorshipPolicyId: sponsorshipPolicy }, ], })); } console.log("Estimating user operation gas..."); return handleRequest(() => this.client.request({ method: "eth_estimateUserOperationGas", params: [userOp, this.entryPointAddress], })); } async sendUserOperation(userOp) { return handleRequest(() => this.client.request({ method: "eth_sendUserOperation", params: [userOp, this.entryPointAddress], })); // throw new Error(`Failed to send user op with: ${error.message}`); } async getGasPrice() { return handleRequest(() => this.client.request({ method: "pimlico_getUserOperationGasPrice", params: [], })); } async getUserOpReceipt(userOpHash) { let userOpReceipt = null; while (!userOpReceipt) { // Wait 2 seconds before checking the status again await new Promise((resolve) => setTimeout(resolve, 2000)); userOpReceipt = await this._getUserOpReceiptInner(userOpHash); } return userOpReceipt; } async _getUserOpReceiptInner(userOpHash) { return handleRequest(() => this.client.request({ method: "eth_getUserOperationReceipt", params: [userOpHash], })); } // New method to query sponsorship policies async getSponsorshipPolicies() { const url = `https://api.pimlico.io/v2/account/sponsorship_policies?apikey=${this.apiKey}`; const allPolocies = await handleRequest(async () => { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}: ${response.statusText}`); } return response.json(); }); return allPolocies.data.filter((p) => p.chain_ids.allowlist.includes(this.chainId)); } } exports.Erc4337Bundler = Erc4337Bundler; async function handleRequest(clientMethod) { try { return await clientMethod(); } catch (error) { const message = stripApiKey(error); if (error instanceof viem_1.HttpRequestError) { if (error.status === 401) { throw new Error("Unauthorized request. Please check your Pimlico API key."); } else { throw new Error(`Pimlico: ${message}`); } } else if (error instanceof viem_1.RpcError) { throw new Error(`Failed to send user op with: ${message}`); } throw new Error(`Bundler Request: ${message}`); } } function stripApiKey(error) { const message = error instanceof Error ? error.message : String(error); return message.replace(/(apikey=)[^\s&]+/, "$1***"); // Could also do this with slicing. // const keyStart = message.indexOf("apikey=") + 7; // // If no apikey in the message, return it as is. // if (keyStart === -1) return message; // return `${message.slice(0, keyStart)}***${message.slice(keyStart + 36)}`; }