near-safe 0.9.8 → 0.9.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,6 @@
1
1
  import { Address, Hash, PublicClient, Transport } from "viem";
2
2
  import { GasPrices, PaymasterData, SponsorshipPolicyData, UnsignedUserOperation, UserOperation, UserOperationGas, UserOperationReceipt } from "../types";
3
+ import { Pimlico } from "./pimlico";
3
4
  type SponsorshipPolicy = {
4
5
  sponsorshipPolicyId: string;
5
6
  };
@@ -33,15 +34,14 @@ type BundlerRpcSchema = [
33
34
  export declare class Erc4337Bundler {
34
35
  client: PublicClient<Transport, undefined, undefined, BundlerRpcSchema>;
35
36
  entryPointAddress: Address;
36
- apiKey: string;
37
+ pimlico: Pimlico;
37
38
  chainId: number;
38
39
  constructor(entryPointAddress: Address, apiKey: string, chainId: number);
39
40
  getPaymasterData(rawUserOp: UnsignedUserOperation, sponsorshipPolicy?: string): Promise<PaymasterData>;
40
41
  sendUserOperation(userOp: UserOperation): Promise<Hash>;
41
42
  getGasPrice(): Promise<GasPrices>;
42
43
  getUserOpReceipt(userOpHash: Hash): Promise<UserOperationReceipt>;
43
- private _getUserOpReceiptInner;
44
44
  getSponsorshipPolicies(): Promise<SponsorshipPolicyData[]>;
45
+ private _getUserOpReceiptInner;
45
46
  }
46
- export declare function stripApiKey(error: unknown): string;
47
47
  export {};
@@ -1,19 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Erc4337Bundler = void 0;
4
- exports.stripApiKey = stripApiKey;
5
4
  const viem_1 = require("viem");
6
5
  const util_1 = require("../util");
7
- function bundlerUrl(chainId, apikey) {
8
- return `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${apikey}`;
9
- }
6
+ const pimlico_1 = require("./pimlico");
10
7
  class Erc4337Bundler {
11
8
  constructor(entryPointAddress, apiKey, chainId) {
12
9
  this.entryPointAddress = entryPointAddress;
13
- this.apiKey = apiKey;
10
+ this.pimlico = new pimlico_1.Pimlico(apiKey);
14
11
  this.chainId = chainId;
15
12
  this.client = (0, viem_1.createPublicClient)({
16
- transport: (0, viem_1.http)(bundlerUrl(chainId, this.apiKey)),
13
+ transport: (0, viem_1.http)(this.pimlico.bundlerUrl(chainId)),
17
14
  rpcSchema: (0, viem_1.rpcSchema)(),
18
15
  });
19
16
  }
@@ -21,7 +18,7 @@ class Erc4337Bundler {
21
18
  const userOp = { ...rawUserOp, signature: util_1.PLACEHOLDER_SIG };
22
19
  if (sponsorshipPolicy) {
23
20
  console.log("Requesting paymaster data...");
24
- return handleRequest(() => this.client.request({
21
+ return this.pimlico.handleRequest(() => this.client.request({
25
22
  method: "pm_sponsorUserOperation",
26
23
  params: [
27
24
  userOp,
@@ -31,20 +28,20 @@ class Erc4337Bundler {
31
28
  }));
32
29
  }
33
30
  console.log("Estimating user operation gas...");
34
- return handleRequest(() => this.client.request({
31
+ return this.pimlico.handleRequest(() => this.client.request({
35
32
  method: "eth_estimateUserOperationGas",
36
33
  params: [userOp, this.entryPointAddress],
37
34
  }));
38
35
  }
39
36
  async sendUserOperation(userOp) {
40
- return handleRequest(() => this.client.request({
37
+ return this.pimlico.handleRequest(() => this.client.request({
41
38
  method: "eth_sendUserOperation",
42
39
  params: [userOp, this.entryPointAddress],
43
40
  }));
44
41
  // throw new Error(`Failed to send user op with: ${error.message}`);
45
42
  }
46
43
  async getGasPrice() {
47
- return handleRequest(() => this.client.request({
44
+ return this.pimlico.handleRequest(() => this.client.request({
48
45
  method: "pimlico_getUserOperationGasPrice",
49
46
  params: [],
50
47
  }));
@@ -58,52 +55,16 @@ class Erc4337Bundler {
58
55
  }
59
56
  return userOpReceipt;
60
57
  }
58
+ async getSponsorshipPolicies() {
59
+ // Chain ID doesn't matter for this bundler endpoint.
60
+ const allPolicies = await this.pimlico.getSponsorshipPolicies();
61
+ return allPolicies.filter((p) => p.chain_ids.allowlist.includes(this.chainId));
62
+ }
61
63
  async _getUserOpReceiptInner(userOpHash) {
62
- return handleRequest(() => this.client.request({
64
+ return this.pimlico.handleRequest(() => this.client.request({
63
65
  method: "eth_getUserOperationReceipt",
64
66
  params: [userOpHash],
65
67
  }));
66
68
  }
67
- // New method to query sponsorship policies
68
- async getSponsorshipPolicies() {
69
- const url = `https://api.pimlico.io/v2/account/sponsorship_policies?apikey=${this.apiKey}`;
70
- const allPolocies = await handleRequest(async () => {
71
- const response = await fetch(url);
72
- if (!response.ok) {
73
- throw new Error(`HTTP error! status: ${response.status}: ${response.statusText}`);
74
- }
75
- return response.json();
76
- });
77
- return allPolocies.data.filter((p) => p.chain_ids.allowlist.includes(this.chainId));
78
- }
79
69
  }
80
70
  exports.Erc4337Bundler = Erc4337Bundler;
81
- async function handleRequest(clientMethod) {
82
- try {
83
- return await clientMethod();
84
- }
85
- catch (error) {
86
- const message = stripApiKey(error);
87
- if (error instanceof viem_1.HttpRequestError) {
88
- if (error.status === 401) {
89
- throw new Error("Unauthorized request. Please check your Pimlico API key.");
90
- }
91
- else {
92
- throw new Error(`Pimlico: ${message}`);
93
- }
94
- }
95
- else if (error instanceof viem_1.RpcError) {
96
- throw new Error(`Failed to send user op with: ${message}`);
97
- }
98
- throw new Error(`Bundler Request: ${message}`);
99
- }
100
- }
101
- function stripApiKey(error) {
102
- const message = error instanceof Error ? error.message : String(error);
103
- return message.replace(/(apikey=)[^\s&]+/, "$1***");
104
- // Could also do this with slicing.
105
- // const keyStart = message.indexOf("apikey=") + 7;
106
- // // If no apikey in the message, return it as is.
107
- // if (keyStart === -1) return message;
108
- // return `${message.slice(0, keyStart)}***${message.slice(keyStart + 36)}`;
109
- }
@@ -0,0 +1,11 @@
1
+ import { SponsorshipPolicyData } from "../types";
2
+ export declare class Pimlico {
3
+ private apiKey;
4
+ constructor(apiKey: string);
5
+ bundlerUrl(chainId: number): string;
6
+ getSponsorshipPolicies(): Promise<SponsorshipPolicyData[]>;
7
+ getSponsorshipPolicyByName(name: string): Promise<SponsorshipPolicyData>;
8
+ getSponsorshipPolicyById(id: string): Promise<SponsorshipPolicyData>;
9
+ handleRequest<T>(clientMethod: () => Promise<T>): Promise<T>;
10
+ }
11
+ export declare function stripApiKey(error: unknown): string;
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Pimlico = void 0;
4
+ exports.stripApiKey = stripApiKey;
5
+ const viem_1 = require("viem");
6
+ class Pimlico {
7
+ constructor(apiKey) {
8
+ this.apiKey = apiKey;
9
+ }
10
+ bundlerUrl(chainId) {
11
+ return `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${this.apiKey}`;
12
+ }
13
+ // New method to query sponsorship policies
14
+ async getSponsorshipPolicies() {
15
+ const url = `https://api.pimlico.io/v2/account/sponsorship_policies?apikey=${this.apiKey}`;
16
+ const allPolicies = await this.handleRequest(async () => {
17
+ const response = await fetch(url);
18
+ if (!response.ok) {
19
+ throw new Error(`HTTP error! status: ${response.status}: ${response.statusText}`);
20
+ }
21
+ return response.json();
22
+ });
23
+ return allPolicies.data;
24
+ }
25
+ async getSponsorshipPolicyByName(name) {
26
+ const allPolicies = await this.getSponsorshipPolicies();
27
+ const result = allPolicies.filter((t) => t.policy_name === name);
28
+ if (result.length === 0) {
29
+ throw new Error(`No policy found with policy_name=${name}: try ${allPolicies.map((t) => t.policy_name)}`);
30
+ }
31
+ else if (result.length > 1) {
32
+ throw new Error(`Multiple Policies with same policy_name=${name}: ${JSON.stringify(result)}`);
33
+ }
34
+ return result[0];
35
+ }
36
+ async getSponsorshipPolicyById(id) {
37
+ const allPolicies = await this.getSponsorshipPolicies();
38
+ const result = allPolicies.filter((t) => t.id === id);
39
+ if (result.length === 0) {
40
+ throw new Error(`No policy found with id=${id}: try ${allPolicies.map((t) => t.id)}`);
41
+ }
42
+ // We assume that ids are unique so that result.length > 1 need not be handled.
43
+ return result[0];
44
+ }
45
+ async handleRequest(clientMethod) {
46
+ try {
47
+ return await clientMethod();
48
+ }
49
+ catch (error) {
50
+ const message = stripApiKey(error);
51
+ if (error instanceof viem_1.HttpRequestError) {
52
+ if (error.status === 401) {
53
+ throw new Error("Unauthorized request. Please check your Pimlico API key.");
54
+ }
55
+ else {
56
+ throw new Error(`Pimlico: ${message}`);
57
+ }
58
+ }
59
+ else if (error instanceof viem_1.RpcError) {
60
+ throw new Error(`Failed to send user op with: ${message}`);
61
+ }
62
+ throw new Error(`Bundler Request: ${message}`);
63
+ }
64
+ }
65
+ }
66
+ exports.Pimlico = Pimlico;
67
+ function stripApiKey(error) {
68
+ const message = error instanceof Error ? error.message : String(error);
69
+ return message.replace(/(apikey=)[^\s&]+/, "$1***");
70
+ // Could also do this with slicing.
71
+ // const keyStart = message.indexOf("apikey=") + 7;
72
+ // // If no apikey in the message, return it as is.
73
+ // if (keyStart === -1) return message;
74
+ // return `${message.slice(0, keyStart)}***${message.slice(keyStart + 36)}`;
75
+ }
@@ -169,7 +169,7 @@ export declare class NearSafe {
169
169
  */
170
170
  requestRouter({ method, chainId, params }: SignRequestData, sponsorshipPolicy?: string): Promise<EncodedSignRequest>;
171
171
  encodeForSafe(from: string): boolean;
172
- policyForChainId(chainId: number): Promise<SponsorshipPolicyData[]>;
172
+ policiesForChainId(chainId: number): Promise<SponsorshipPolicyData[]>;
173
173
  deploymentRequest(chainId: number): SignRequestData;
174
174
  addOwnerRequest(chainId: number, recoveryAddress: Address): SignRequestData;
175
175
  }
@@ -346,9 +346,8 @@ class NearSafe {
346
346
  }
347
347
  return [this.address.toLowerCase(), lowerZero].includes(lowerFrom);
348
348
  }
349
- async policyForChainId(chainId) {
350
- const bundler = this.bundlerForChainId(chainId);
351
- return bundler.getSponsorshipPolicies();
349
+ async policiesForChainId(chainId) {
350
+ return this.bundlerForChainId(chainId).getSponsorshipPolicies();
352
351
  }
353
352
  deploymentRequest(chainId) {
354
353
  return {
@@ -1,5 +1,6 @@
1
1
  import { Address, Hash, PublicClient, Transport } from "viem";
2
2
  import { GasPrices, PaymasterData, SponsorshipPolicyData, UnsignedUserOperation, UserOperation, UserOperationGas, UserOperationReceipt } from "../types";
3
+ import { Pimlico } from "./pimlico";
3
4
  type SponsorshipPolicy = {
4
5
  sponsorshipPolicyId: string;
5
6
  };
@@ -33,15 +34,14 @@ type BundlerRpcSchema = [
33
34
  export declare class Erc4337Bundler {
34
35
  client: PublicClient<Transport, undefined, undefined, BundlerRpcSchema>;
35
36
  entryPointAddress: Address;
36
- apiKey: string;
37
+ pimlico: Pimlico;
37
38
  chainId: number;
38
39
  constructor(entryPointAddress: Address, apiKey: string, chainId: number);
39
40
  getPaymasterData(rawUserOp: UnsignedUserOperation, sponsorshipPolicy?: string): Promise<PaymasterData>;
40
41
  sendUserOperation(userOp: UserOperation): Promise<Hash>;
41
42
  getGasPrice(): Promise<GasPrices>;
42
43
  getUserOpReceipt(userOpHash: Hash): Promise<UserOperationReceipt>;
43
- private _getUserOpReceiptInner;
44
44
  getSponsorshipPolicies(): Promise<SponsorshipPolicyData[]>;
45
+ private _getUserOpReceiptInner;
45
46
  }
46
- export declare function stripApiKey(error: unknown): string;
47
47
  export {};
@@ -1,19 +1,17 @@
1
- import { createPublicClient, http, rpcSchema, RpcError, HttpRequestError, } from "viem";
1
+ import { createPublicClient, http, rpcSchema, } from "viem";
2
2
  import { PLACEHOLDER_SIG } from "../util";
3
- function bundlerUrl(chainId, apikey) {
4
- return `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${apikey}`;
5
- }
3
+ import { Pimlico } from "./pimlico";
6
4
  export class Erc4337Bundler {
7
5
  client;
8
6
  entryPointAddress;
9
- apiKey;
7
+ pimlico;
10
8
  chainId;
11
9
  constructor(entryPointAddress, apiKey, chainId) {
12
10
  this.entryPointAddress = entryPointAddress;
13
- this.apiKey = apiKey;
11
+ this.pimlico = new Pimlico(apiKey);
14
12
  this.chainId = chainId;
15
13
  this.client = createPublicClient({
16
- transport: http(bundlerUrl(chainId, this.apiKey)),
14
+ transport: http(this.pimlico.bundlerUrl(chainId)),
17
15
  rpcSchema: rpcSchema(),
18
16
  });
19
17
  }
@@ -21,7 +19,7 @@ export class Erc4337Bundler {
21
19
  const userOp = { ...rawUserOp, signature: PLACEHOLDER_SIG };
22
20
  if (sponsorshipPolicy) {
23
21
  console.log("Requesting paymaster data...");
24
- return handleRequest(() => this.client.request({
22
+ return this.pimlico.handleRequest(() => this.client.request({
25
23
  method: "pm_sponsorUserOperation",
26
24
  params: [
27
25
  userOp,
@@ -31,20 +29,20 @@ export class Erc4337Bundler {
31
29
  }));
32
30
  }
33
31
  console.log("Estimating user operation gas...");
34
- return handleRequest(() => this.client.request({
32
+ return this.pimlico.handleRequest(() => this.client.request({
35
33
  method: "eth_estimateUserOperationGas",
36
34
  params: [userOp, this.entryPointAddress],
37
35
  }));
38
36
  }
39
37
  async sendUserOperation(userOp) {
40
- return handleRequest(() => this.client.request({
38
+ return this.pimlico.handleRequest(() => this.client.request({
41
39
  method: "eth_sendUserOperation",
42
40
  params: [userOp, this.entryPointAddress],
43
41
  }));
44
42
  // throw new Error(`Failed to send user op with: ${error.message}`);
45
43
  }
46
44
  async getGasPrice() {
47
- return handleRequest(() => this.client.request({
45
+ return this.pimlico.handleRequest(() => this.client.request({
48
46
  method: "pimlico_getUserOperationGasPrice",
49
47
  params: [],
50
48
  }));
@@ -58,51 +56,15 @@ export class Erc4337Bundler {
58
56
  }
59
57
  return userOpReceipt;
60
58
  }
59
+ async getSponsorshipPolicies() {
60
+ // Chain ID doesn't matter for this bundler endpoint.
61
+ const allPolicies = await this.pimlico.getSponsorshipPolicies();
62
+ return allPolicies.filter((p) => p.chain_ids.allowlist.includes(this.chainId));
63
+ }
61
64
  async _getUserOpReceiptInner(userOpHash) {
62
- return handleRequest(() => this.client.request({
65
+ return this.pimlico.handleRequest(() => this.client.request({
63
66
  method: "eth_getUserOperationReceipt",
64
67
  params: [userOpHash],
65
68
  }));
66
69
  }
67
- // New method to query sponsorship policies
68
- async getSponsorshipPolicies() {
69
- const url = `https://api.pimlico.io/v2/account/sponsorship_policies?apikey=${this.apiKey}`;
70
- const allPolocies = await handleRequest(async () => {
71
- const response = await fetch(url);
72
- if (!response.ok) {
73
- throw new Error(`HTTP error! status: ${response.status}: ${response.statusText}`);
74
- }
75
- return response.json();
76
- });
77
- return allPolocies.data.filter((p) => p.chain_ids.allowlist.includes(this.chainId));
78
- }
79
- }
80
- async function handleRequest(clientMethod) {
81
- try {
82
- return await clientMethod();
83
- }
84
- catch (error) {
85
- const message = stripApiKey(error);
86
- if (error instanceof HttpRequestError) {
87
- if (error.status === 401) {
88
- throw new Error("Unauthorized request. Please check your Pimlico API key.");
89
- }
90
- else {
91
- throw new Error(`Pimlico: ${message}`);
92
- }
93
- }
94
- else if (error instanceof RpcError) {
95
- throw new Error(`Failed to send user op with: ${message}`);
96
- }
97
- throw new Error(`Bundler Request: ${message}`);
98
- }
99
- }
100
- export function stripApiKey(error) {
101
- const message = error instanceof Error ? error.message : String(error);
102
- return message.replace(/(apikey=)[^\s&]+/, "$1***");
103
- // Could also do this with slicing.
104
- // const keyStart = message.indexOf("apikey=") + 7;
105
- // // If no apikey in the message, return it as is.
106
- // if (keyStart === -1) return message;
107
- // return `${message.slice(0, keyStart)}***${message.slice(keyStart + 36)}`;
108
70
  }
@@ -0,0 +1,11 @@
1
+ import { SponsorshipPolicyData } from "../types";
2
+ export declare class Pimlico {
3
+ private apiKey;
4
+ constructor(apiKey: string);
5
+ bundlerUrl(chainId: number): string;
6
+ getSponsorshipPolicies(): Promise<SponsorshipPolicyData[]>;
7
+ getSponsorshipPolicyByName(name: string): Promise<SponsorshipPolicyData>;
8
+ getSponsorshipPolicyById(id: string): Promise<SponsorshipPolicyData>;
9
+ handleRequest<T>(clientMethod: () => Promise<T>): Promise<T>;
10
+ }
11
+ export declare function stripApiKey(error: unknown): string;
@@ -0,0 +1,71 @@
1
+ import { HttpRequestError, RpcError } from "viem";
2
+ export class Pimlico {
3
+ apiKey;
4
+ constructor(apiKey) {
5
+ this.apiKey = apiKey;
6
+ }
7
+ bundlerUrl(chainId) {
8
+ return `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${this.apiKey}`;
9
+ }
10
+ // New method to query sponsorship policies
11
+ async getSponsorshipPolicies() {
12
+ const url = `https://api.pimlico.io/v2/account/sponsorship_policies?apikey=${this.apiKey}`;
13
+ const allPolicies = await this.handleRequest(async () => {
14
+ const response = await fetch(url);
15
+ if (!response.ok) {
16
+ throw new Error(`HTTP error! status: ${response.status}: ${response.statusText}`);
17
+ }
18
+ return response.json();
19
+ });
20
+ return allPolicies.data;
21
+ }
22
+ async getSponsorshipPolicyByName(name) {
23
+ const allPolicies = await this.getSponsorshipPolicies();
24
+ const result = allPolicies.filter((t) => t.policy_name === name);
25
+ if (result.length === 0) {
26
+ throw new Error(`No policy found with policy_name=${name}: try ${allPolicies.map((t) => t.policy_name)}`);
27
+ }
28
+ else if (result.length > 1) {
29
+ throw new Error(`Multiple Policies with same policy_name=${name}: ${JSON.stringify(result)}`);
30
+ }
31
+ return result[0];
32
+ }
33
+ async getSponsorshipPolicyById(id) {
34
+ const allPolicies = await this.getSponsorshipPolicies();
35
+ const result = allPolicies.filter((t) => t.id === id);
36
+ if (result.length === 0) {
37
+ throw new Error(`No policy found with id=${id}: try ${allPolicies.map((t) => t.id)}`);
38
+ }
39
+ // We assume that ids are unique so that result.length > 1 need not be handled.
40
+ return result[0];
41
+ }
42
+ async handleRequest(clientMethod) {
43
+ try {
44
+ return await clientMethod();
45
+ }
46
+ catch (error) {
47
+ const message = stripApiKey(error);
48
+ if (error instanceof HttpRequestError) {
49
+ if (error.status === 401) {
50
+ throw new Error("Unauthorized request. Please check your Pimlico API key.");
51
+ }
52
+ else {
53
+ throw new Error(`Pimlico: ${message}`);
54
+ }
55
+ }
56
+ else if (error instanceof RpcError) {
57
+ throw new Error(`Failed to send user op with: ${message}`);
58
+ }
59
+ throw new Error(`Bundler Request: ${message}`);
60
+ }
61
+ }
62
+ }
63
+ export function stripApiKey(error) {
64
+ const message = error instanceof Error ? error.message : String(error);
65
+ return message.replace(/(apikey=)[^\s&]+/, "$1***");
66
+ // Could also do this with slicing.
67
+ // const keyStart = message.indexOf("apikey=") + 7;
68
+ // // If no apikey in the message, return it as is.
69
+ // if (keyStart === -1) return message;
70
+ // return `${message.slice(0, keyStart)}***${message.slice(keyStart + 36)}`;
71
+ }
@@ -169,7 +169,7 @@ export declare class NearSafe {
169
169
  */
170
170
  requestRouter({ method, chainId, params }: SignRequestData, sponsorshipPolicy?: string): Promise<EncodedSignRequest>;
171
171
  encodeForSafe(from: string): boolean;
172
- policyForChainId(chainId: number): Promise<SponsorshipPolicyData[]>;
172
+ policiesForChainId(chainId: number): Promise<SponsorshipPolicyData[]>;
173
173
  deploymentRequest(chainId: number): SignRequestData;
174
174
  addOwnerRequest(chainId: number, recoveryAddress: Address): SignRequestData;
175
175
  }
@@ -349,9 +349,8 @@ export class NearSafe {
349
349
  }
350
350
  return [this.address.toLowerCase(), lowerZero].includes(lowerFrom);
351
351
  }
352
- async policyForChainId(chainId) {
353
- const bundler = this.bundlerForChainId(chainId);
354
- return bundler.getSponsorshipPolicies();
352
+ async policiesForChainId(chainId) {
353
+ return this.bundlerForChainId(chainId).getSponsorshipPolicies();
355
354
  }
356
355
  deploymentRequest(chainId) {
357
356
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "near-safe",
3
- "version": "0.9.8",
3
+ "version": "0.9.10",
4
4
  "license": "MIT",
5
5
  "description": "An SDK for controlling Ethereum Smart Accounts via ERC4337 from a Near Account.",
6
6
  "author": "bh2smith",