near-safe 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }