near-safe 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,15 +1,37 @@
1
- import { ethers } from "ethers";
1
+ import { Address, Hash, PublicClient, Transport } from "viem";
2
2
  import { GasPrices, PaymasterData, UnsignedUserOperation, UserOperation, UserOperationReceipt } from "../types";
3
+ type BundlerRpcSchema = [
4
+ {
5
+ Method: "pm_sponsorUserOperation";
6
+ Parameters: [UnsignedUserOperation, Address];
7
+ ReturnType: PaymasterData;
8
+ },
9
+ {
10
+ Method: "eth_sendUserOperation";
11
+ Parameters: [UserOperation, Address];
12
+ ReturnType: Hash;
13
+ },
14
+ {
15
+ Method: "pimlico_getUserOperationGasPrice";
16
+ Parameters: [];
17
+ ReturnType: GasPrices;
18
+ },
19
+ {
20
+ Method: "eth_getUserOperationReceipt";
21
+ Parameters: [Hash];
22
+ ReturnType: UserOperationReceipt | null;
23
+ }
24
+ ];
3
25
  export declare class Erc4337Bundler {
4
- provider: ethers.JsonRpcProvider;
5
- entryPointAddress: string;
26
+ client: PublicClient<Transport, undefined, undefined, BundlerRpcSchema>;
27
+ entryPointAddress: Address;
6
28
  apiKey: string;
7
29
  chainId: number;
8
- constructor(entryPointAddress: string, apiKey: string, chainId: number);
9
- client(chainId: number): ethers.JsonRpcProvider;
30
+ constructor(entryPointAddress: Address, apiKey: string, chainId: number);
10
31
  getPaymasterData(rawUserOp: UnsignedUserOperation, usePaymaster: boolean, safeNotDeployed: boolean): Promise<PaymasterData>;
11
- sendUserOperation(userOp: UserOperation): Promise<string>;
32
+ sendUserOperation(userOp: UserOperation): Promise<Hash>;
12
33
  getGasPrice(): Promise<GasPrices>;
13
- _getUserOpReceiptInner(userOpHash: string): Promise<UserOperationReceipt | null>;
14
- getUserOpReceipt(userOpHash: string): Promise<UserOperationReceipt>;
34
+ getUserOpReceipt(userOpHash: Hash): Promise<UserOperationReceipt>;
35
+ private _getUserOpReceiptInner;
15
36
  }
37
+ export {};
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Erc4337Bundler = void 0;
4
- // TODO: Ethers dependency is only for Generic HTTP Provider
5
- const ethers_1 = require("ethers");
6
4
  const viem_1 = require("viem");
7
5
  const util_1 = require("../util");
8
6
  function bundlerUrl(chainId, apikey) {
@@ -13,41 +11,37 @@ class Erc4337Bundler {
13
11
  this.entryPointAddress = entryPointAddress;
14
12
  this.apiKey = apiKey;
15
13
  this.chainId = chainId;
16
- this.provider = new ethers_1.ethers.JsonRpcProvider(bundlerUrl(chainId, apiKey));
17
- }
18
- client(chainId) {
19
- return new ethers_1.ethers.JsonRpcProvider(bundlerUrl(chainId, this.apiKey));
14
+ this.client = (0, viem_1.createPublicClient)({
15
+ transport: (0, viem_1.http)(bundlerUrl(chainId, this.apiKey)),
16
+ rpcSchema: (0, viem_1.rpcSchema)(),
17
+ });
20
18
  }
21
19
  async getPaymasterData(rawUserOp, usePaymaster, safeNotDeployed) {
22
20
  // TODO: Keep this option out of the bundler
23
21
  if (usePaymaster) {
24
22
  console.log("Requesting paymaster data...");
25
- const data = this.provider.send("pm_sponsorUserOperation", [
26
- { ...rawUserOp, signature: util_1.PLACEHOLDER_SIG },
27
- this.entryPointAddress,
28
- ]);
29
- return data;
23
+ return handleRequest(() => this.client.request({
24
+ method: "pm_sponsorUserOperation",
25
+ params: [
26
+ { ...rawUserOp, signature: util_1.PLACEHOLDER_SIG },
27
+ this.entryPointAddress,
28
+ ],
29
+ }));
30
30
  }
31
31
  return defaultPaymasterData(safeNotDeployed);
32
32
  }
33
33
  async sendUserOperation(userOp) {
34
- try {
35
- const userOpHash = await this.provider.send("eth_sendUserOperation", [
36
- userOp,
37
- this.entryPointAddress,
38
- ]);
39
- return userOpHash;
40
- }
41
- catch (err) {
42
- const error = err.error;
43
- throw new Error(`Failed to send user op with: ${error.message}`);
44
- }
34
+ return handleRequest(() => this.client.request({
35
+ method: "eth_sendUserOperation",
36
+ params: [userOp, this.entryPointAddress],
37
+ }));
38
+ // throw new Error(`Failed to send user op with: ${error.message}`);
45
39
  }
46
40
  async getGasPrice() {
47
- return this.provider.send("pimlico_getUserOperationGasPrice", []);
48
- }
49
- async _getUserOpReceiptInner(userOpHash) {
50
- return this.provider.send("eth_getUserOperationReceipt", [userOpHash]);
41
+ return handleRequest(() => this.client.request({
42
+ method: "pimlico_getUserOperationGasPrice",
43
+ params: [],
44
+ }));
51
45
  }
52
46
  async getUserOpReceipt(userOpHash) {
53
47
  let userOpReceipt = null;
@@ -58,8 +52,33 @@ class Erc4337Bundler {
58
52
  }
59
53
  return userOpReceipt;
60
54
  }
55
+ async _getUserOpReceiptInner(userOpHash) {
56
+ return handleRequest(() => this.client.request({
57
+ method: "eth_getUserOperationReceipt",
58
+ params: [userOpHash],
59
+ }));
60
+ }
61
61
  }
62
62
  exports.Erc4337Bundler = Erc4337Bundler;
63
+ async function handleRequest(clientMethod) {
64
+ try {
65
+ return await clientMethod();
66
+ }
67
+ catch (error) {
68
+ if (error instanceof viem_1.HttpRequestError) {
69
+ if (error.status === 401) {
70
+ throw new Error("Unauthorized request. Please check your API key.");
71
+ }
72
+ else {
73
+ console.error(`Request failed with status ${error.status}: ${error.message}`);
74
+ }
75
+ }
76
+ else if (error instanceof viem_1.RpcError) {
77
+ throw new Error(`Failed to send user op with: ${error.message}`);
78
+ }
79
+ throw new Error(`Unexpected error ${error instanceof Error ? error.message : String(error)}`);
80
+ }
81
+ }
63
82
  // TODO(bh2smith) Should probably get reasonable estimates here:
64
83
  const defaultPaymasterData = (safeNotDeployed) => {
65
84
  return {
@@ -0,0 +1,27 @@
1
+ import { type SafeInfo } from "@safe-global/safe-gateway-typescript-sdk";
2
+ import { EIP712TypedData, RecoveryData } from "near-ca";
3
+ import { Address, Hash } from "viem";
4
+ export type DecodedSafeMessage = {
5
+ decodedMessage: string | EIP712TypedData;
6
+ safeMessageMessage: string;
7
+ safeMessageHash: Hash;
8
+ };
9
+ export type MinimalSafeInfo = Pick<SafeInfo, "address" | "version" | "chainId">;
10
+ /**
11
+ * Returns the decoded message, the hash of the `message` and the hash of the `safeMessage`.
12
+ * The `safeMessageMessage` is the value inside the SafeMessage and the `safeMessageHash` gets signed if the connected wallet does not support `eth_signTypedData`.
13
+ *
14
+ * @param message message as string, UTF-8 encoded hex string or EIP-712 Typed Data
15
+ * @param safe SafeInfo of the opened Safe
16
+ * @returns `{
17
+ * decodedMessage,
18
+ * safeMessageMessage,
19
+ * safeMessageHash
20
+ * }`
21
+ */
22
+ export declare function decodeSafeMessage(message: string | EIP712TypedData, safe: MinimalSafeInfo): DecodedSafeMessage;
23
+ export declare function safeMessageTxData(method: string, message: DecodedSafeMessage, sender: Address): {
24
+ evmMessage: string;
25
+ payload: number[];
26
+ recoveryData: RecoveryData;
27
+ };
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decodeSafeMessage = decodeSafeMessage;
4
+ exports.safeMessageTxData = safeMessageTxData;
5
+ const near_ca_1 = require("near-ca");
6
+ const semver_1 = require("semver");
7
+ const viem_1 = require("viem");
8
+ /*
9
+ * From v1.3.0, EIP-1271 support was moved to the CompatibilityFallbackHandler.
10
+ * Also 1.3.0 introduces the chainId in the domain part of the SafeMessage
11
+ */
12
+ const EIP1271_FALLBACK_HANDLER_SUPPORTED_SAFE_VERSION = "1.3.0";
13
+ const generateSafeMessageMessage = (message) => {
14
+ return typeof message === "string"
15
+ ? (0, viem_1.hashMessage)(message)
16
+ : (0, viem_1.hashTypedData)(message);
17
+ };
18
+ /**
19
+ * Generates `SafeMessage` typed data for EIP-712
20
+ * https://github.com/safe-global/safe-contracts/blob/main/contracts/handler/CompatibilityFallbackHandler.sol#L12
21
+ * @param safe Safe which will sign the message
22
+ * @param message Message to sign
23
+ * @returns `SafeMessage` types for signing
24
+ */
25
+ const generateSafeMessageTypedData = ({ version, chainId, address }, message) => {
26
+ if (!version) {
27
+ throw Error("Cannot create SafeMessage without version information");
28
+ }
29
+ const isHandledByFallbackHandler = (0, semver_1.gte)(version, EIP1271_FALLBACK_HANDLER_SUPPORTED_SAFE_VERSION);
30
+ const verifyingContract = address.value;
31
+ return {
32
+ domain: isHandledByFallbackHandler
33
+ ? {
34
+ chainId: Number(BigInt(chainId)),
35
+ verifyingContract,
36
+ }
37
+ : { verifyingContract },
38
+ types: {
39
+ SafeMessage: [{ name: "message", type: "bytes" }],
40
+ },
41
+ message: {
42
+ message: generateSafeMessageMessage(message),
43
+ },
44
+ primaryType: "SafeMessage",
45
+ };
46
+ };
47
+ const generateSafeMessageHash = (safe, message) => {
48
+ const typedData = generateSafeMessageTypedData(safe, message);
49
+ return (0, viem_1.hashTypedData)(typedData);
50
+ };
51
+ /**
52
+ * If message is a hex value and is Utf8 encoded string we decode it, else we return the raw message
53
+ * @param {string} message raw input message
54
+ * @returns {string}
55
+ */
56
+ const getDecodedMessage = (message) => {
57
+ if ((0, viem_1.isHex)(message)) {
58
+ try {
59
+ return (0, viem_1.fromHex)(message, "string");
60
+ }
61
+ catch (e) {
62
+ // the hex string is not UTF8 encoding so return the raw message.
63
+ }
64
+ }
65
+ return message;
66
+ };
67
+ /**
68
+ * Returns the decoded message, the hash of the `message` and the hash of the `safeMessage`.
69
+ * The `safeMessageMessage` is the value inside the SafeMessage and the `safeMessageHash` gets signed if the connected wallet does not support `eth_signTypedData`.
70
+ *
71
+ * @param message message as string, UTF-8 encoded hex string or EIP-712 Typed Data
72
+ * @param safe SafeInfo of the opened Safe
73
+ * @returns `{
74
+ * decodedMessage,
75
+ * safeMessageMessage,
76
+ * safeMessageHash
77
+ * }`
78
+ */
79
+ function decodeSafeMessage(message, safe) {
80
+ const decodedMessage = typeof message === "string" ? getDecodedMessage(message) : message;
81
+ return {
82
+ decodedMessage,
83
+ safeMessageMessage: generateSafeMessageMessage(decodedMessage),
84
+ safeMessageHash: generateSafeMessageHash(safe, decodedMessage),
85
+ };
86
+ }
87
+ function safeMessageTxData(method, message, sender) {
88
+ return {
89
+ evmMessage: message.safeMessageMessage,
90
+ payload: (0, near_ca_1.toPayload)(message.safeMessageHash),
91
+ recoveryData: {
92
+ type: method,
93
+ data: {
94
+ address: sender,
95
+ // TODO - Upgrade Signable Message in near-ca
96
+ // @ts-expect-error: Type 'string | EIP712TypedData' is not assignable to type 'SignableMessage'.
97
+ message: decodedMessage,
98
+ },
99
+ },
100
+ };
101
+ }
102
+ // const isEIP712TypedData = (obj: any): obj is EIP712TypedData => {
103
+ // return (
104
+ // typeof obj === "object" &&
105
+ // obj != null &&
106
+ // "domain" in obj &&
107
+ // "types" in obj &&
108
+ // "message" in obj
109
+ // );
110
+ // };
111
+ // export const isBlindSigningPayload = (obj: EIP712TypedData | string): boolean =>
112
+ // !isEIP712TypedData(obj) && isHash(obj);
@@ -1,24 +1,27 @@
1
- import { ethers } from "ethers";
2
- import { Address, Hash, Hex } from "viem";
1
+ import { Address, Hash, Hex, ParseAbi, PublicClient } from "viem";
3
2
  import { GasPrice, MetaTransaction, UnsignedUserOperation, UserOperation } from "../types";
3
+ interface DeploymentData {
4
+ abi: unknown[] | ParseAbi<readonly string[]>;
5
+ address: `0x${string}`;
6
+ }
4
7
  /**
5
8
  * All contracts used in account creation & execution
6
9
  */
7
10
  export declare class ContractSuite {
8
- provider: ethers.JsonRpcProvider;
9
- singleton: ethers.Contract;
10
- proxyFactory: ethers.Contract;
11
- m4337: ethers.Contract;
12
- moduleSetup: ethers.Contract;
13
- entryPoint: ethers.Contract;
14
- constructor(provider: ethers.JsonRpcProvider, singleton: ethers.Contract, proxyFactory: ethers.Contract, m4337: ethers.Contract, moduleSetup: ethers.Contract, entryPoint: ethers.Contract);
11
+ dummyClient: PublicClient;
12
+ singleton: DeploymentData;
13
+ proxyFactory: DeploymentData;
14
+ m4337: DeploymentData;
15
+ moduleSetup: DeploymentData;
16
+ entryPoint: DeploymentData;
17
+ constructor(client: PublicClient, singleton: DeploymentData, proxyFactory: DeploymentData, m4337: DeploymentData, moduleSetup: DeploymentData, entryPoint: DeploymentData);
15
18
  static init(): Promise<ContractSuite>;
16
- addressForSetup(setup: ethers.BytesLike, saltNonce?: string): Promise<Address>;
17
- getSetup(owners: string[]): Promise<Hex>;
19
+ addressForSetup(setup: Hex, saltNonce?: string): Promise<Address>;
20
+ getSetup(owners: string[]): Hex;
21
+ addOwnerData(newOwner: Address): Hex;
18
22
  getOpHash(unsignedUserOp: UserOperation): Promise<Hash>;
19
- factoryDataForSetup(safeNotDeployed: boolean, setup: string, safeSaltNonce: string): {
20
- factory?: Address;
21
- factoryData?: Hex;
22
- };
23
- buildUserOp(txData: MetaTransaction, safeAddress: Address, feeData: GasPrice, setup: string, safeNotDeployed: boolean, safeSaltNonce: string): Promise<UnsignedUserOperation>;
23
+ private factoryDataForSetup;
24
+ buildUserOp(nonce: bigint, txData: MetaTransaction, safeAddress: Address, feeData: GasPrice, setup: string, safeNotDeployed: boolean, safeSaltNonce: string): Promise<UnsignedUserOperation>;
25
+ getNonce(address: Address, chainId: number): Promise<bigint>;
24
26
  }
27
+ export {};
@@ -3,14 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ContractSuite = void 0;
4
4
  const safe_deployments_1 = require("@safe-global/safe-deployments");
5
5
  const safe_modules_deployments_1 = require("@safe-global/safe-modules-deployments");
6
- const ethers_1 = require("ethers");
6
+ const viem_1 = require("viem");
7
7
  const util_1 = require("../util");
8
8
  /**
9
9
  * All contracts used in account creation & execution
10
10
  */
11
11
  class ContractSuite {
12
- constructor(provider, singleton, proxyFactory, m4337, moduleSetup, entryPoint) {
13
- this.provider = provider;
12
+ constructor(client, singleton, proxyFactory, m4337, moduleSetup, entryPoint) {
13
+ this.dummyClient = client;
14
14
  this.singleton = singleton;
15
15
  this.proxyFactory = proxyFactory;
16
16
  this.m4337 = m4337;
@@ -19,109 +19,155 @@ class ContractSuite {
19
19
  }
20
20
  static async init() {
21
21
  // TODO - this is a cheeky hack.
22
- const provider = new ethers_1.ethers.JsonRpcProvider("https://rpc2.sepolia.org");
23
- const safeDeployment = (fn) => getDeployment(fn, { provider, version: "1.4.1" });
22
+ const client = (0, util_1.getClient)(11155111);
23
+ const safeDeployment = (fn) => getDeployment(fn, { version: "1.4.1" });
24
24
  const m4337Deployment = async (fn) => {
25
- return getDeployment(fn, { provider, version: "0.3.0" });
25
+ return getDeployment(fn, { version: "0.3.0" });
26
26
  };
27
- // Need this first to get entryPoint address
28
- const m4337 = await m4337Deployment(safe_modules_deployments_1.getSafe4337ModuleDeployment);
29
- const [singleton, proxyFactory, moduleSetup, supportedEntryPoint] = await Promise.all([
27
+ const [singleton, proxyFactory, moduleSetup, m4337] = await Promise.all([
30
28
  safeDeployment(safe_deployments_1.getSafeL2SingletonDeployment),
31
29
  safeDeployment(safe_deployments_1.getProxyFactoryDeployment),
32
30
  m4337Deployment(safe_modules_deployments_1.getSafeModuleSetupDeployment),
33
- m4337.SUPPORTED_ENTRYPOINT(),
31
+ m4337Deployment(safe_modules_deployments_1.getSafe4337ModuleDeployment),
34
32
  ]);
35
- const entryPoint = new ethers_1.ethers.Contract(supportedEntryPoint, ["function getNonce(address, uint192 key) view returns (uint256 nonce)"], provider);
36
- console.log("Initialized ERC4337 & Safe Module Contracts:", {
37
- singleton: await singleton.getAddress(),
38
- proxyFactory: await proxyFactory.getAddress(),
39
- m4337: await m4337.getAddress(),
40
- moduleSetup: await moduleSetup.getAddress(),
41
- entryPoint: await entryPoint.getAddress(),
33
+ // console.log("Initialized ERC4337 & Safe Module Contracts:", {
34
+ // singleton: await singleton.getAddress(),
35
+ // proxyFactory: await proxyFactory.getAddress(),
36
+ // m4337: await m4337.getAddress(),
37
+ // moduleSetup: await moduleSetup.getAddress(),
38
+ // entryPoint: await entryPoint.getAddress(),
39
+ // });
40
+ return new ContractSuite(client, singleton, proxyFactory, m4337, moduleSetup,
41
+ // EntryPoint:
42
+ {
43
+ address: (await client.readContract({
44
+ address: m4337.address,
45
+ abi: m4337.abi,
46
+ functionName: "SUPPORTED_ENTRYPOINT",
47
+ })),
48
+ abi: (0, viem_1.parseAbi)([
49
+ "function getNonce(address, uint192 key) view returns (uint256 nonce)",
50
+ ]),
42
51
  });
43
- return new ContractSuite(provider, singleton, proxyFactory, m4337, moduleSetup, entryPoint);
44
52
  }
45
53
  async addressForSetup(setup, saltNonce) {
46
54
  // bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce));
47
55
  // cf: https://github.com/safe-global/safe-smart-account/blob/499b17ad0191b575fcadc5cb5b8e3faeae5391ae/contracts/proxies/SafeProxyFactory.sol#L58
48
- const salt = ethers_1.ethers.keccak256(ethers_1.ethers.solidityPacked(["bytes32", "uint256"], [ethers_1.ethers.keccak256(setup), saltNonce || 0]));
56
+ const salt = (0, viem_1.keccak256)((0, viem_1.encodePacked)(["bytes32", "uint256"], [(0, viem_1.keccak256)(setup), BigInt(saltNonce || "0")]));
49
57
  // abi.encodePacked(type(SafeProxy).creationCode, uint256(uint160(_singleton)));
50
58
  // cf: https://github.com/safe-global/safe-smart-account/blob/499b17ad0191b575fcadc5cb5b8e3faeae5391ae/contracts/proxies/SafeProxyFactory.sol#L29
51
- const initCode = ethers_1.ethers.solidityPacked(["bytes", "uint256"], [
52
- await this.proxyFactory.proxyCreationCode(),
53
- await this.singleton.getAddress(),
59
+ const initCode = (0, viem_1.encodePacked)(["bytes", "uint256"], [
60
+ (await this.dummyClient.readContract({
61
+ address: this.proxyFactory.address,
62
+ abi: this.proxyFactory.abi,
63
+ functionName: "proxyCreationCode",
64
+ })),
65
+ BigInt(this.singleton.address),
54
66
  ]);
55
- return ethers_1.ethers.getCreate2Address(await this.proxyFactory.getAddress(), salt, ethers_1.ethers.keccak256(initCode));
67
+ return (0, viem_1.getCreate2Address)({
68
+ from: this.proxyFactory.address,
69
+ salt,
70
+ bytecodeHash: (0, viem_1.keccak256)(initCode),
71
+ });
56
72
  }
57
- async getSetup(owners) {
58
- const setup = await this.singleton.interface.encodeFunctionData("setup", [
59
- owners,
60
- 1, // We use sign threshold of 1.
61
- this.moduleSetup.target,
62
- this.moduleSetup.interface.encodeFunctionData("enableModules", [
63
- [this.m4337.target],
64
- ]),
65
- this.m4337.target,
66
- ethers_1.ethers.ZeroAddress,
67
- 0,
68
- ethers_1.ethers.ZeroAddress,
69
- ]);
70
- return setup;
73
+ getSetup(owners) {
74
+ return (0, viem_1.encodeFunctionData)({
75
+ abi: this.singleton.abi,
76
+ functionName: "setup",
77
+ args: [
78
+ owners,
79
+ 1, // We use sign threshold of 1.
80
+ this.moduleSetup.address,
81
+ (0, viem_1.encodeFunctionData)({
82
+ abi: this.moduleSetup.abi,
83
+ functionName: "enableModules",
84
+ args: [[this.m4337.address]],
85
+ }),
86
+ this.m4337.address,
87
+ viem_1.zeroAddress,
88
+ 0,
89
+ viem_1.zeroAddress,
90
+ ],
91
+ });
92
+ }
93
+ addOwnerData(newOwner) {
94
+ return (0, viem_1.encodeFunctionData)({
95
+ abi: this.singleton.abi,
96
+ functionName: "addOwnerWithThreshold",
97
+ args: [newOwner, 1],
98
+ });
71
99
  }
72
100
  async getOpHash(unsignedUserOp) {
73
101
  const { factory, factoryData, verificationGasLimit, callGasLimit, maxPriorityFeePerGas, maxFeePerGas, } = unsignedUserOp;
74
- return this.m4337.getOperationHash({
75
- ...unsignedUserOp,
76
- initCode: factory
77
- ? ethers_1.ethers.solidityPacked(["address", "bytes"], [factory, factoryData])
78
- : "0x",
79
- accountGasLimits: (0, util_1.packGas)(verificationGasLimit, callGasLimit),
80
- gasFees: (0, util_1.packGas)(maxPriorityFeePerGas, maxFeePerGas),
81
- paymasterAndData: (0, util_1.packPaymasterData)(unsignedUserOp),
82
- signature: util_1.PLACEHOLDER_SIG,
102
+ const opHash = await this.dummyClient.readContract({
103
+ address: this.m4337.address,
104
+ abi: this.m4337.abi,
105
+ functionName: "getOperationHash",
106
+ args: [
107
+ {
108
+ ...unsignedUserOp,
109
+ initCode: factory
110
+ ? (0, viem_1.encodePacked)(["address", "bytes"], [factory, factoryData])
111
+ : "0x",
112
+ accountGasLimits: (0, util_1.packGas)(verificationGasLimit, callGasLimit),
113
+ gasFees: (0, util_1.packGas)(maxPriorityFeePerGas, maxFeePerGas),
114
+ paymasterAndData: (0, util_1.packPaymasterData)(unsignedUserOp),
115
+ signature: util_1.PLACEHOLDER_SIG,
116
+ },
117
+ ],
83
118
  });
119
+ return opHash;
84
120
  }
85
121
  factoryDataForSetup(safeNotDeployed, setup, safeSaltNonce) {
86
122
  return safeNotDeployed
87
123
  ? {
88
- factory: this.proxyFactory.target,
89
- factoryData: this.proxyFactory.interface.encodeFunctionData("createProxyWithNonce", [this.singleton.target, setup, safeSaltNonce]),
124
+ factory: this.proxyFactory.address,
125
+ factoryData: (0, viem_1.encodeFunctionData)({
126
+ abi: this.proxyFactory.abi,
127
+ functionName: "createProxyWithNonce",
128
+ args: [this.singleton.address, setup, safeSaltNonce],
129
+ }),
90
130
  }
91
131
  : {};
92
132
  }
93
- async buildUserOp(txData, safeAddress, feeData, setup, safeNotDeployed, safeSaltNonce) {
94
- const rawUserOp = {
133
+ async buildUserOp(nonce, txData, safeAddress, feeData, setup, safeNotDeployed, safeSaltNonce) {
134
+ return {
95
135
  sender: safeAddress,
96
- nonce: ethers_1.ethers.toBeHex(await this.entryPoint.getNonce(safeAddress, 0)),
136
+ nonce: (0, viem_1.toHex)(nonce),
97
137
  ...this.factoryDataForSetup(safeNotDeployed, setup, safeSaltNonce),
98
138
  // <https://github.com/safe-global/safe-modules/blob/9a18245f546bf2a8ed9bdc2b04aae44f949ec7a0/modules/4337/contracts/Safe4337Module.sol#L172>
99
- callData: this.m4337.interface.encodeFunctionData("executeUserOp", [
100
- txData.to,
101
- BigInt(txData.value),
102
- txData.data,
103
- txData.operation || 0,
104
- ]),
139
+ callData: (0, viem_1.encodeFunctionData)({
140
+ abi: this.m4337.abi,
141
+ functionName: "executeUserOp",
142
+ args: [
143
+ txData.to,
144
+ BigInt(txData.value),
145
+ txData.data,
146
+ txData.operation || 0,
147
+ ],
148
+ }),
105
149
  ...feeData,
106
150
  };
107
- return rawUserOp;
151
+ }
152
+ async getNonce(address, chainId) {
153
+ const nonce = (await (0, util_1.getClient)(chainId).readContract({
154
+ abi: this.entryPoint.abi,
155
+ address: this.entryPoint.address,
156
+ functionName: "getNonce",
157
+ args: [address, 0],
158
+ }));
159
+ return nonce;
108
160
  }
109
161
  }
110
162
  exports.ContractSuite = ContractSuite;
111
- async function getDeployment(fn, { provider, version }) {
112
- const { chainId } = await provider.getNetwork();
163
+ async function getDeployment(fn, { version }) {
113
164
  const deployment = fn({ version });
114
165
  if (!deployment) {
115
- throw new Error(`Deployment not found for ${fn.name} version ${version} on chainId ${chainId}`);
116
- }
117
- let address = deployment.networkAddresses[`${chainId}`];
118
- if (!address) {
119
- // console.warn(
120
- // `Deployment asset ${fn.name} not listed on chainId ${chainId}, using likely fallback. For more info visit https://github.com/safe-global/safe-modules-deployments`
121
- // );
122
- // TODO: This is a cheeky hack. Real solution proposed in
123
- // https://github.com/Mintbase/near-safe/issues/42
124
- address = deployment.networkAddresses["11155111"];
166
+ throw new Error(`Deployment not found for ${fn.name} version ${version}`);
125
167
  }
126
- return new ethers_1.ethers.Contract(address, deployment.abi, provider);
168
+ // TODO: maybe call parseAbi on deployment.abi here.
169
+ return {
170
+ address: deployment.networkAddresses["11155111"],
171
+ abi: deployment.abi,
172
+ };
127
173
  }
@@ -1,5 +1,5 @@
1
1
  import { FinalExecutionOutcome } from "near-api-js/lib/providers";
2
- import { NearEthAdapter, NearEthTxData, BaseTx } from "near-ca";
2
+ import { NearEthAdapter, SignRequestData, NearEthTxData, RecoveryData } from "near-ca";
3
3
  import { Address, Hash, Hex } from "viem";
4
4
  import { Erc4337Bundler } from "./lib/bundler";
5
5
  import { ContractSuite } from "./lib/safe";
@@ -7,13 +7,12 @@ import { MetaTransaction, UserOperation, UserOperationReceipt } from "./types";
7
7
  export declare class TransactionManager {
8
8
  readonly nearAdapter: NearEthAdapter;
9
9
  readonly address: Address;
10
- readonly entryPointAddress: Address;
11
10
  private safePack;
12
11
  private setup;
13
12
  private pimlicoKey;
14
13
  private safeSaltNonce;
15
14
  private deployedChains;
16
- constructor(nearAdapter: NearEthAdapter, safePack: ContractSuite, pimlicoKey: string, setup: string, safeAddress: Address, entryPointAddress: Address, safeSaltNonce: string);
15
+ constructor(nearAdapter: NearEthAdapter, safePack: ContractSuite, pimlicoKey: string, setup: string, safeAddress: Address, safeSaltNonce: string);
17
16
  static create(config: {
18
17
  accountId: string;
19
18
  mpcContractId: string;
@@ -22,6 +21,7 @@ export declare class TransactionManager {
22
21
  safeSaltNonce?: string;
23
22
  }): Promise<TransactionManager>;
24
23
  get mpcAddress(): Address;
24
+ get mpcContractId(): string;
25
25
  getBalance(chainId: number): Promise<bigint>;
26
26
  bundlerForChainId(chainId: number): Erc4337Bundler;
27
27
  buildTransaction(args: {
@@ -31,13 +31,28 @@ export declare class TransactionManager {
31
31
  }): Promise<UserOperation>;
32
32
  signTransaction(safeOpHash: Hex): Promise<Hex>;
33
33
  opHash(userOp: UserOperation): Promise<Hash>;
34
- encodeSignRequest(tx: BaseTx): Promise<NearEthTxData>;
34
+ encodeSignRequest(signRequest: SignRequestData, usePaymaster: boolean): Promise<NearEthTxData>;
35
35
  executeTransaction(chainId: number, userOp: UserOperation): Promise<UserOperationReceipt>;
36
36
  safeDeployed(chainId: number): Promise<boolean>;
37
- addOwnerTx(address: string): MetaTransaction;
37
+ addOwnerTx(address: Address): MetaTransaction;
38
38
  safeSufficientlyFunded(chainId: number, transactions: MetaTransaction[], gasCost: bigint): Promise<boolean>;
39
39
  broadcastEvm(chainId: number, outcome: FinalExecutionOutcome, unsignedUserOp: UserOperation): Promise<{
40
40
  signature: Hex;
41
41
  receipt: UserOperationReceipt;
42
42
  }>;
43
+ /**
44
+ * Handles routing of signature requests based on the provided method, chain ID, and parameters.
45
+ *
46
+ * @async
47
+ * @function requestRouter
48
+ * @param {SignRequestData} params - An object containing the method, chain ID, and request parameters.
49
+ * @returns {Promise<{ evmMessage: string; payload: number[]; recoveryData: RecoveryData }>}
50
+ * - Returns a promise that resolves to an object containing the Ethereum Virtual Machine (EVM) message,
51
+ * the payload (hashed data), and recovery data needed for reconstructing the signature request.
52
+ */
53
+ requestRouter({ method, chainId, params }: SignRequestData, usePaymaster: boolean): Promise<{
54
+ evmMessage: string;
55
+ payload: number[];
56
+ recoveryData: RecoveryData;
57
+ }>;
43
58
  }