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.
- package/dist/cjs/lib/bundler.d.ts +30 -8
- package/dist/cjs/lib/bundler.js +45 -26
- package/dist/cjs/lib/safe-message.d.ts +27 -0
- package/dist/cjs/lib/safe-message.js +112 -0
- package/dist/cjs/lib/safe.d.ts +19 -16
- package/dist/cjs/lib/safe.js +117 -71
- package/dist/cjs/tx-manager.d.ts +20 -5
- package/dist/cjs/tx-manager.js +80 -37
- package/dist/cjs/util.d.ts +5 -1
- package/dist/cjs/util.js +34 -0
- package/dist/esm/lib/bundler.d.ts +30 -8
- package/dist/esm/lib/bundler.js +47 -28
- package/dist/esm/lib/safe-message.d.ts +27 -0
- package/dist/esm/lib/safe-message.js +108 -0
- package/dist/esm/lib/safe.d.ts +19 -16
- package/dist/esm/lib/safe.js +120 -73
- package/dist/esm/tx-manager.d.ts +20 -5
- package/dist/esm/tx-manager.js +82 -40
- package/dist/esm/util.d.ts +5 -1
- package/dist/esm/util.js +32 -1
- package/package.json +11 -5
@@ -1,15 +1,37 @@
|
|
1
|
-
import {
|
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
|
-
|
5
|
-
entryPointAddress:
|
26
|
+
client: PublicClient<Transport, undefined, undefined, BundlerRpcSchema>;
|
27
|
+
entryPointAddress: Address;
|
6
28
|
apiKey: string;
|
7
29
|
chainId: number;
|
8
|
-
constructor(entryPointAddress:
|
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<
|
32
|
+
sendUserOperation(userOp: UserOperation): Promise<Hash>;
|
12
33
|
getGasPrice(): Promise<GasPrices>;
|
13
|
-
|
14
|
-
|
34
|
+
getUserOpReceipt(userOpHash: Hash): Promise<UserOperationReceipt>;
|
35
|
+
private _getUserOpReceiptInner;
|
15
36
|
}
|
37
|
+
export {};
|
package/dist/cjs/lib/bundler.js
CHANGED
@@ -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.
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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.
|
48
|
-
|
49
|
-
|
50
|
-
|
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);
|
package/dist/cjs/lib/safe.d.ts
CHANGED
@@ -1,24 +1,27 @@
|
|
1
|
-
import {
|
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
|
-
|
9
|
-
singleton:
|
10
|
-
proxyFactory:
|
11
|
-
m4337:
|
12
|
-
moduleSetup:
|
13
|
-
entryPoint:
|
14
|
-
constructor(
|
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:
|
17
|
-
getSetup(owners: string[]):
|
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
|
20
|
-
|
21
|
-
|
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 {};
|
package/dist/cjs/lib/safe.js
CHANGED
@@ -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
|
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(
|
13
|
-
this.
|
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
|
23
|
-
const safeDeployment = (fn) => getDeployment(fn, {
|
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, {
|
25
|
+
return getDeployment(fn, { version: "0.3.0" });
|
26
26
|
};
|
27
|
-
|
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
|
-
|
31
|
+
m4337Deployment(safe_modules_deployments_1.getSafe4337ModuleDeployment),
|
34
32
|
]);
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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 =
|
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 =
|
52
|
-
await this.
|
53
|
-
|
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
|
67
|
+
return (0, viem_1.getCreate2Address)({
|
68
|
+
from: this.proxyFactory.address,
|
69
|
+
salt,
|
70
|
+
bytecodeHash: (0, viem_1.keccak256)(initCode),
|
71
|
+
});
|
56
72
|
}
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
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.
|
89
|
-
factoryData:
|
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
|
-
|
133
|
+
async buildUserOp(nonce, txData, safeAddress, feeData, setup, safeNotDeployed, safeSaltNonce) {
|
134
|
+
return {
|
95
135
|
sender: safeAddress,
|
96
|
-
nonce:
|
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:
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
-
|
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, {
|
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}
|
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
|
-
|
168
|
+
// TODO: maybe call parseAbi on deployment.abi here.
|
169
|
+
return {
|
170
|
+
address: deployment.networkAddresses["11155111"],
|
171
|
+
abi: deployment.abi,
|
172
|
+
};
|
127
173
|
}
|
package/dist/cjs/tx-manager.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { FinalExecutionOutcome } from "near-api-js/lib/providers";
|
2
|
-
import { NearEthAdapter, NearEthTxData,
|
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,
|
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(
|
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:
|
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
|
}
|