near-safe 0.3.1 → 0.4.0
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/scripts/fetch-deployments.d.ts +17 -0
- package/dist/cjs/scripts/fetch-deployments.js +59 -0
- package/dist/cjs/src/_gen/deployments.d.ts +2 -0
- package/dist/cjs/src/_gen/deployments.js +1889 -0
- package/dist/cjs/{index.d.ts → src/index.d.ts} +1 -1
- package/dist/cjs/{index.js → src/index.js} +1 -1
- package/dist/{esm → cjs/src}/lib/bundler.d.ts +1 -0
- package/dist/cjs/{lib → src/lib}/bundler.js +15 -4
- package/dist/cjs/{lib → src/lib}/safe-message.d.ts +2 -7
- package/dist/cjs/{lib → src/lib}/safe-message.js +0 -17
- package/dist/cjs/src/lib/safe.d.ts +21 -0
- package/dist/cjs/{lib → src/lib}/safe.js +12 -56
- package/dist/cjs/{tx-manager.d.ts → src/near-safe.d.ts} +22 -21
- package/dist/cjs/{tx-manager.js → src/near-safe.js} +65 -63
- package/dist/cjs/{types.d.ts → src/types.d.ts} +23 -1
- package/dist/esm/scripts/fetch-deployments.d.ts +17 -0
- package/dist/esm/scripts/fetch-deployments.js +54 -0
- package/dist/esm/src/_gen/deployments.d.ts +2 -0
- package/dist/esm/src/_gen/deployments.js +1886 -0
- package/dist/esm/{index.d.ts → src/index.d.ts} +1 -1
- package/dist/esm/{index.js → src/index.js} +1 -1
- package/dist/{cjs → esm/src}/lib/bundler.d.ts +1 -0
- package/dist/esm/{lib → src/lib}/bundler.js +14 -4
- package/dist/esm/{lib → src/lib}/safe-message.d.ts +2 -7
- package/dist/esm/{lib → src/lib}/safe-message.js +0 -16
- package/dist/esm/src/lib/safe.d.ts +21 -0
- package/dist/esm/{lib → src/lib}/safe.js +11 -55
- package/dist/esm/{tx-manager.d.ts → src/near-safe.d.ts} +22 -21
- package/dist/esm/{tx-manager.js → src/near-safe.js} +65 -64
- package/dist/esm/{types.d.ts → src/types.d.ts} +23 -1
- package/package.json +4 -3
- package/dist/cjs/lib/safe.d.ts +0 -27
- package/dist/esm/lib/safe.d.ts +0 -27
- /package/dist/cjs/{lib → src/lib}/multisend.d.ts +0 -0
- /package/dist/cjs/{lib → src/lib}/multisend.js +0 -0
- /package/dist/cjs/{types.js → src/types.js} +0 -0
- /package/dist/cjs/{util.d.ts → src/util.d.ts} +0 -0
- /package/dist/cjs/{util.js → src/util.js} +0 -0
- /package/dist/esm/{lib → src/lib}/multisend.d.ts +0 -0
- /package/dist/esm/{lib → src/lib}/multisend.js +0 -0
- /package/dist/esm/{types.js → src/types.js} +0 -0
- /package/dist/esm/{util.d.ts → src/util.d.ts} +0 -0
- /package/dist/esm/{util.js → src/util.js} +0 -0
@@ -15,7 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
15
15
|
};
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
17
17
|
exports.populateTx = exports.Network = void 0;
|
18
|
-
__exportStar(require("./
|
18
|
+
__exportStar(require("./near-safe"), exports);
|
19
19
|
__exportStar(require("./types"), exports);
|
20
20
|
__exportStar(require("./util"), exports);
|
21
21
|
var near_ca_1 = require("near-ca");
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.Erc4337Bundler = void 0;
|
4
|
+
exports.stripApiKey = stripApiKey;
|
4
5
|
const viem_1 = require("viem");
|
5
6
|
const util_1 = require("../util");
|
6
7
|
function bundlerUrl(chainId, apikey) {
|
@@ -65,18 +66,19 @@ async function handleRequest(clientMethod) {
|
|
65
66
|
return await clientMethod();
|
66
67
|
}
|
67
68
|
catch (error) {
|
69
|
+
const message = stripApiKey(error);
|
68
70
|
if (error instanceof viem_1.HttpRequestError) {
|
69
71
|
if (error.status === 401) {
|
70
|
-
throw new Error("Unauthorized request. Please check your API key.");
|
72
|
+
throw new Error("Unauthorized request. Please check your Pimlico API key.");
|
71
73
|
}
|
72
74
|
else {
|
73
|
-
|
75
|
+
throw new Error(`Pimlico: ${message}`);
|
74
76
|
}
|
75
77
|
}
|
76
78
|
else if (error instanceof viem_1.RpcError) {
|
77
|
-
throw new Error(`Failed to send user op with: ${
|
79
|
+
throw new Error(`Failed to send user op with: ${message}`);
|
78
80
|
}
|
79
|
-
throw new Error(`
|
81
|
+
throw new Error(`Bundler Request: ${message}`);
|
80
82
|
}
|
81
83
|
}
|
82
84
|
// TODO(bh2smith) Should probably get reasonable estimates here:
|
@@ -87,3 +89,12 @@ const defaultPaymasterData = (safeNotDeployed) => {
|
|
87
89
|
preVerificationGas: (0, viem_1.toHex)(100000),
|
88
90
|
};
|
89
91
|
};
|
92
|
+
function stripApiKey(error) {
|
93
|
+
const message = error instanceof Error ? error.message : String(error);
|
94
|
+
return message.replace(/(apikey=)[^\s&]+/, "$1***");
|
95
|
+
// Could also do this with slicing.
|
96
|
+
// const keyStart = message.indexOf("apikey=") + 7;
|
97
|
+
// // If no apikey in the message, return it as is.
|
98
|
+
// if (keyStart === -1) return message;
|
99
|
+
// return `${message.slice(0, keyStart)}***${message.slice(keyStart + 36)}`;
|
100
|
+
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { type SafeInfo } from "@safe-global/safe-gateway-typescript-sdk";
|
2
|
-
import { EIP712TypedData
|
3
|
-
import {
|
2
|
+
import { EIP712TypedData } from "near-ca";
|
3
|
+
import { Hash } from "viem";
|
4
4
|
export type DecodedSafeMessage = {
|
5
5
|
decodedMessage: string | EIP712TypedData;
|
6
6
|
safeMessageMessage: string;
|
@@ -20,8 +20,3 @@ export type MinimalSafeInfo = Pick<SafeInfo, "address" | "version" | "chainId">;
|
|
20
20
|
* }`
|
21
21
|
*/
|
22
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
|
-
};
|
@@ -1,8 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.decodeSafeMessage = decodeSafeMessage;
|
4
|
-
exports.safeMessageTxData = safeMessageTxData;
|
5
|
-
const near_ca_1 = require("near-ca");
|
6
4
|
const semver_1 = require("semver");
|
7
5
|
const viem_1 = require("viem");
|
8
6
|
/*
|
@@ -84,21 +82,6 @@ function decodeSafeMessage(message, safe) {
|
|
84
82
|
safeMessageHash: generateSafeMessageHash(safe, decodedMessage),
|
85
83
|
};
|
86
84
|
}
|
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
85
|
// const isEIP712TypedData = (obj: any): obj is EIP712TypedData => {
|
103
86
|
// return (
|
104
87
|
// typeof obj === "object" &&
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { Address, Hash, Hex, PublicClient } from "viem";
|
2
|
+
import { Deployment, GasPrice, MetaTransaction, UnsignedUserOperation, UserOperation } from "../types";
|
3
|
+
/**
|
4
|
+
* All contracts used in account creation & execution
|
5
|
+
*/
|
6
|
+
export declare class SafeContractSuite {
|
7
|
+
dummyClient: PublicClient;
|
8
|
+
singleton: Deployment;
|
9
|
+
proxyFactory: Deployment;
|
10
|
+
m4337: Deployment;
|
11
|
+
moduleSetup: Deployment;
|
12
|
+
entryPoint: Deployment;
|
13
|
+
constructor();
|
14
|
+
addressForSetup(setup: Hex, saltNonce?: string): Promise<Address>;
|
15
|
+
getSetup(owners: string[]): Hex;
|
16
|
+
addOwnerData(newOwner: Address): Hex;
|
17
|
+
getOpHash(unsignedUserOp: UserOperation): Promise<Hash>;
|
18
|
+
private factoryDataForSetup;
|
19
|
+
buildUserOp(nonce: bigint, txData: MetaTransaction, safeAddress: Address, feeData: GasPrice, setup: string, safeNotDeployed: boolean, safeSaltNonce: string): Promise<UnsignedUserOperation>;
|
20
|
+
getNonce(address: Address, chainId: number): Promise<bigint>;
|
21
|
+
}
|
@@ -1,54 +1,21 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.
|
4
|
-
const safe_deployments_1 = require("@safe-global/safe-deployments");
|
5
|
-
const safe_modules_deployments_1 = require("@safe-global/safe-modules-deployments");
|
3
|
+
exports.SafeContractSuite = void 0;
|
6
4
|
const viem_1 = require("viem");
|
5
|
+
const deployments_1 = require("../_gen/deployments");
|
7
6
|
const util_1 = require("../util");
|
8
7
|
/**
|
9
8
|
* All contracts used in account creation & execution
|
10
9
|
*/
|
11
|
-
class
|
12
|
-
constructor(
|
13
|
-
this.dummyClient =
|
14
|
-
|
15
|
-
this.
|
16
|
-
this.
|
17
|
-
this.
|
18
|
-
this.
|
19
|
-
|
20
|
-
static async init() {
|
21
|
-
// TODO - this is a cheeky hack.
|
22
|
-
const client = (0, util_1.getClient)(11155111);
|
23
|
-
const safeDeployment = (fn) => getDeployment(fn, { version: "1.4.1" });
|
24
|
-
const m4337Deployment = async (fn) => {
|
25
|
-
return getDeployment(fn, { version: "0.3.0" });
|
26
|
-
};
|
27
|
-
const [singleton, proxyFactory, moduleSetup, m4337] = await Promise.all([
|
28
|
-
safeDeployment(safe_deployments_1.getSafeL2SingletonDeployment),
|
29
|
-
safeDeployment(safe_deployments_1.getProxyFactoryDeployment),
|
30
|
-
m4337Deployment(safe_modules_deployments_1.getSafeModuleSetupDeployment),
|
31
|
-
m4337Deployment(safe_modules_deployments_1.getSafe4337ModuleDeployment),
|
32
|
-
]);
|
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
|
-
]),
|
51
|
-
});
|
10
|
+
class SafeContractSuite {
|
11
|
+
constructor() {
|
12
|
+
this.dummyClient = (0, util_1.getClient)(11155111);
|
13
|
+
const deployments = deployments_1.SAFE_DEPLOYMENTS;
|
14
|
+
this.singleton = deployments.singleton;
|
15
|
+
this.proxyFactory = deployments.proxyFactory;
|
16
|
+
this.m4337 = deployments.m4337;
|
17
|
+
this.moduleSetup = deployments.moduleSetup;
|
18
|
+
this.entryPoint = deployments.entryPoint;
|
52
19
|
}
|
53
20
|
async addressForSetup(setup, saltNonce) {
|
54
21
|
// bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce));
|
@@ -159,15 +126,4 @@ class ContractSuite {
|
|
159
126
|
return nonce;
|
160
127
|
}
|
161
128
|
}
|
162
|
-
exports.
|
163
|
-
async function getDeployment(fn, { version }) {
|
164
|
-
const deployment = fn({ version });
|
165
|
-
if (!deployment) {
|
166
|
-
throw new Error(`Deployment not found for ${fn.name} version ${version}`);
|
167
|
-
}
|
168
|
-
// TODO: maybe call parseAbi on deployment.abi here.
|
169
|
-
return {
|
170
|
-
address: deployment.networkAddresses["11155111"],
|
171
|
-
abi: deployment.abi,
|
172
|
-
};
|
173
|
-
}
|
129
|
+
exports.SafeContractSuite = SafeContractSuite;
|
@@ -1,29 +1,29 @@
|
|
1
|
+
import { NearConfig } from "near-api-js/lib/near";
|
1
2
|
import { FinalExecutionOutcome } from "near-api-js/lib/providers";
|
2
|
-
import { NearEthAdapter, SignRequestData
|
3
|
+
import { NearEthAdapter, SignRequestData } from "near-ca";
|
3
4
|
import { Address, Hash, Hex } from "viem";
|
4
|
-
import {
|
5
|
-
import {
|
6
|
-
|
7
|
-
|
5
|
+
import { SafeContractSuite } from "./lib/safe";
|
6
|
+
import { EncodedTxData, MetaTransaction, UserOperation, UserOperationReceipt } from "./types";
|
7
|
+
export interface NearSafeConfig {
|
8
|
+
accountId: string;
|
9
|
+
mpcContractId: string;
|
10
|
+
pimlicoKey: string;
|
11
|
+
nearConfig?: NearConfig;
|
12
|
+
privateKey?: string;
|
13
|
+
safeSaltNonce?: string;
|
14
|
+
}
|
15
|
+
export declare class NearSafe {
|
8
16
|
readonly nearAdapter: NearEthAdapter;
|
9
17
|
readonly address: Address;
|
10
18
|
private safePack;
|
11
19
|
private setup;
|
12
20
|
private pimlicoKey;
|
13
21
|
private safeSaltNonce;
|
14
|
-
|
15
|
-
constructor(nearAdapter: NearEthAdapter, safePack:
|
16
|
-
static create(config: {
|
17
|
-
accountId: string;
|
18
|
-
mpcContractId: string;
|
19
|
-
pimlicoKey: string;
|
20
|
-
privateKey?: string;
|
21
|
-
safeSaltNonce?: string;
|
22
|
-
}): Promise<TransactionManager>;
|
22
|
+
static create(config: NearSafeConfig): Promise<NearSafe>;
|
23
|
+
constructor(nearAdapter: NearEthAdapter, safePack: SafeContractSuite, pimlicoKey: string, setup: string, safeAddress: Address, safeSaltNonce: string);
|
23
24
|
get mpcAddress(): Address;
|
24
25
|
get mpcContractId(): string;
|
25
26
|
getBalance(chainId: number): Promise<bigint>;
|
26
|
-
bundlerForChainId(chainId: number): Erc4337Bundler;
|
27
27
|
buildTransaction(args: {
|
28
28
|
chainId: number;
|
29
29
|
transactions: MetaTransaction[];
|
@@ -31,15 +31,16 @@ export declare class TransactionManager {
|
|
31
31
|
}): Promise<UserOperation>;
|
32
32
|
signTransaction(safeOpHash: Hex): Promise<Hex>;
|
33
33
|
opHash(userOp: UserOperation): Promise<Hash>;
|
34
|
-
encodeSignRequest(signRequest: SignRequestData, usePaymaster: boolean): Promise<
|
35
|
-
executeTransaction(chainId: number, userOp: UserOperation): Promise<UserOperationReceipt>;
|
36
|
-
safeDeployed(chainId: number): Promise<boolean>;
|
37
|
-
addOwnerTx(address: Address): MetaTransaction;
|
38
|
-
safeSufficientlyFunded(chainId: number, transactions: MetaTransaction[], gasCost: bigint): Promise<boolean>;
|
34
|
+
encodeSignRequest(signRequest: SignRequestData, usePaymaster: boolean): Promise<EncodedTxData>;
|
39
35
|
broadcastEvm(chainId: number, outcome: FinalExecutionOutcome, unsignedUserOp: UserOperation): Promise<{
|
40
36
|
signature: Hex;
|
41
37
|
receipt: UserOperationReceipt;
|
42
38
|
}>;
|
39
|
+
executeTransaction(chainId: number, userOp: UserOperation): Promise<UserOperationReceipt>;
|
40
|
+
safeDeployed(chainId: number): Promise<boolean>;
|
41
|
+
sufficientlyFunded(chainId: number, transactions: MetaTransaction[], gasCost: bigint): Promise<boolean>;
|
42
|
+
addOwnerTx(address: Address): MetaTransaction;
|
43
|
+
private bundlerForChainId;
|
43
44
|
/**
|
44
45
|
* Handles routing of signature requests based on the provided method, chain ID, and parameters.
|
45
46
|
*
|
@@ -53,6 +54,6 @@ export declare class TransactionManager {
|
|
53
54
|
requestRouter({ method, chainId, params }: SignRequestData, usePaymaster: boolean): Promise<{
|
54
55
|
evmMessage: string;
|
55
56
|
payload: number[];
|
56
|
-
|
57
|
+
hash: Hash;
|
57
58
|
}>;
|
58
59
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.
|
3
|
+
exports.NearSafe = void 0;
|
4
4
|
const near_ca_1 = require("near-ca");
|
5
5
|
const viem_1 = require("viem");
|
6
6
|
const bundler_1 = require("./lib/bundler");
|
@@ -8,27 +8,28 @@ const multisend_1 = require("./lib/multisend");
|
|
8
8
|
const safe_1 = require("./lib/safe");
|
9
9
|
const safe_message_1 = require("./lib/safe-message");
|
10
10
|
const util_1 = require("./util");
|
11
|
-
class
|
11
|
+
class NearSafe {
|
12
|
+
static async create(config) {
|
13
|
+
const { pimlicoKey, safeSaltNonce } = config;
|
14
|
+
const nearAdapter = await (0, near_ca_1.setupAdapter)({ ...config });
|
15
|
+
const safePack = new safe_1.SafeContractSuite();
|
16
|
+
const setup = safePack.getSetup([nearAdapter.address]);
|
17
|
+
const safeAddress = await safePack.addressForSetup(setup, safeSaltNonce);
|
18
|
+
console.log(`
|
19
|
+
Near Adapter:
|
20
|
+
Near Account ID: ${nearAdapter.nearAccountId()}
|
21
|
+
MPC EOA: ${nearAdapter.address}
|
22
|
+
Safe: ${safeAddress}
|
23
|
+
`);
|
24
|
+
return new NearSafe(nearAdapter, safePack, pimlicoKey, setup, safeAddress, safeSaltNonce || "0");
|
25
|
+
}
|
12
26
|
constructor(nearAdapter, safePack, pimlicoKey, setup, safeAddress, safeSaltNonce) {
|
13
27
|
this.nearAdapter = nearAdapter;
|
28
|
+
this.address = safeAddress;
|
29
|
+
this.setup = setup;
|
14
30
|
this.safePack = safePack;
|
15
31
|
this.pimlicoKey = pimlicoKey;
|
16
|
-
this.setup = setup;
|
17
|
-
this.address = safeAddress;
|
18
32
|
this.safeSaltNonce = safeSaltNonce;
|
19
|
-
this.deployedChains = new Set();
|
20
|
-
}
|
21
|
-
static async create(config) {
|
22
|
-
const { pimlicoKey } = config;
|
23
|
-
const [nearAdapter, safePack] = await Promise.all([
|
24
|
-
(0, near_ca_1.setupAdapter)({ ...config }),
|
25
|
-
safe_1.ContractSuite.init(),
|
26
|
-
]);
|
27
|
-
console.log(`Near Adapter: ${nearAdapter.nearAccountId()} <> ${nearAdapter.address}`);
|
28
|
-
const setup = safePack.getSetup([nearAdapter.address]);
|
29
|
-
const safeAddress = await safePack.addressForSetup(setup, config.safeSaltNonce);
|
30
|
-
console.log(`Safe Address: ${safeAddress}`);
|
31
|
-
return new TransactionManager(nearAdapter, safePack, pimlicoKey, setup, safeAddress, config.safeSaltNonce || "0");
|
32
33
|
}
|
33
34
|
get mpcAddress() {
|
34
35
|
return this.nearAdapter.address;
|
@@ -39,9 +40,6 @@ class TransactionManager {
|
|
39
40
|
async getBalance(chainId) {
|
40
41
|
return await (0, util_1.getClient)(chainId).getBalance({ address: this.address });
|
41
42
|
}
|
42
|
-
bundlerForChainId(chainId) {
|
43
|
-
return new bundler_1.Erc4337Bundler(this.safePack.entryPoint.address, this.pimlicoKey, chainId);
|
44
|
-
}
|
45
43
|
async buildTransaction(args) {
|
46
44
|
const { transactions, usePaymaster, chainId } = args;
|
47
45
|
if (transactions.length === 0) {
|
@@ -68,16 +66,35 @@ class TransactionManager {
|
|
68
66
|
return this.safePack.getOpHash(userOp);
|
69
67
|
}
|
70
68
|
async encodeSignRequest(signRequest, usePaymaster) {
|
71
|
-
const
|
69
|
+
const { payload, evmMessage, hash } = await this.requestRouter(signRequest, usePaymaster);
|
72
70
|
return {
|
73
71
|
nearPayload: await this.nearAdapter.mpcContract.encodeSignatureRequestTx({
|
74
72
|
path: this.nearAdapter.derivationPath,
|
75
|
-
payload
|
73
|
+
payload,
|
76
74
|
key_version: 0,
|
77
75
|
}),
|
78
|
-
|
76
|
+
evmData: {
|
77
|
+
chainId: signRequest.chainId,
|
78
|
+
data: evmMessage,
|
79
|
+
hash,
|
80
|
+
},
|
79
81
|
};
|
80
82
|
}
|
83
|
+
async broadcastEvm(chainId, outcome, unsignedUserOp) {
|
84
|
+
const signature = (0, util_1.packSignature)((0, viem_1.serializeSignature)((0, near_ca_1.signatureFromOutcome)(outcome)));
|
85
|
+
try {
|
86
|
+
return {
|
87
|
+
signature,
|
88
|
+
receipt: await this.executeTransaction(chainId, {
|
89
|
+
...unsignedUserOp,
|
90
|
+
signature,
|
91
|
+
}),
|
92
|
+
};
|
93
|
+
}
|
94
|
+
catch (error) {
|
95
|
+
throw new Error(`Failed EVM broadcast: ${error instanceof Error ? error.message : String(error)}`);
|
96
|
+
}
|
97
|
+
}
|
81
98
|
async executeTransaction(chainId, userOp) {
|
82
99
|
const bundler = this.bundlerForChainId(chainId);
|
83
100
|
const userOpHash = await bundler.sendUserOperation(userOp);
|
@@ -89,15 +106,15 @@ class TransactionManager {
|
|
89
106
|
return userOpReceipt;
|
90
107
|
}
|
91
108
|
async safeDeployed(chainId) {
|
92
|
-
|
93
|
-
|
109
|
+
return (0, util_1.isContract)(this.address, chainId);
|
110
|
+
}
|
111
|
+
async sufficientlyFunded(chainId, transactions, gasCost) {
|
112
|
+
const txValue = transactions.reduce((acc, tx) => acc + BigInt(tx.value), 0n);
|
113
|
+
if (txValue + gasCost === 0n) {
|
94
114
|
return true;
|
95
115
|
}
|
96
|
-
const
|
97
|
-
|
98
|
-
this.deployedChains.add(chainId);
|
99
|
-
}
|
100
|
-
return deployed;
|
116
|
+
const safeBalance = await this.getBalance(chainId);
|
117
|
+
return txValue + gasCost < safeBalance;
|
101
118
|
}
|
102
119
|
addOwnerTx(address) {
|
103
120
|
return {
|
@@ -106,28 +123,8 @@ class TransactionManager {
|
|
106
123
|
data: this.safePack.addOwnerData(address),
|
107
124
|
};
|
108
125
|
}
|
109
|
-
|
110
|
-
|
111
|
-
if (txValue + gasCost === 0n) {
|
112
|
-
return true;
|
113
|
-
}
|
114
|
-
const safeBalance = await this.getBalance(chainId);
|
115
|
-
return txValue + gasCost < safeBalance;
|
116
|
-
}
|
117
|
-
async broadcastEvm(chainId, outcome, unsignedUserOp) {
|
118
|
-
const signature = (0, util_1.packSignature)((0, viem_1.serializeSignature)((0, near_ca_1.signatureFromOutcome)(outcome)));
|
119
|
-
try {
|
120
|
-
return {
|
121
|
-
signature,
|
122
|
-
receipt: await this.executeTransaction(chainId, {
|
123
|
-
...unsignedUserOp,
|
124
|
-
signature,
|
125
|
-
}),
|
126
|
-
};
|
127
|
-
}
|
128
|
-
catch (error) {
|
129
|
-
throw new Error(`Failed EVM broadcast: ${error instanceof Error ? error.message : String(error)}`);
|
130
|
-
}
|
126
|
+
bundlerForChainId(chainId) {
|
127
|
+
return new bundler_1.Erc4337Bundler(this.safePack.entryPoint.address, this.pimlicoKey, chainId);
|
131
128
|
}
|
132
129
|
/**
|
133
130
|
* Handles routing of signature requests based on the provided method, chain ID, and parameters.
|
@@ -152,12 +149,22 @@ class TransactionManager {
|
|
152
149
|
case "eth_signTypedData":
|
153
150
|
case "eth_signTypedData_v4":
|
154
151
|
case "eth_sign": {
|
155
|
-
const [
|
156
|
-
|
152
|
+
const [_, messageOrData] = params;
|
153
|
+
const message = (0, safe_message_1.decodeSafeMessage)(messageOrData, safeInfo);
|
154
|
+
return {
|
155
|
+
evmMessage: message.safeMessageMessage,
|
156
|
+
payload: (0, near_ca_1.toPayload)(message.safeMessageHash),
|
157
|
+
hash: message.safeMessageHash,
|
158
|
+
};
|
157
159
|
}
|
158
160
|
case "personal_sign": {
|
159
|
-
const [messageHash,
|
160
|
-
|
161
|
+
const [messageHash, _] = params;
|
162
|
+
const message = (0, safe_message_1.decodeSafeMessage)(messageHash, safeInfo);
|
163
|
+
return {
|
164
|
+
evmMessage: message.safeMessageMessage,
|
165
|
+
payload: (0, near_ca_1.toPayload)(message.safeMessageHash),
|
166
|
+
hash: message.safeMessageHash,
|
167
|
+
};
|
161
168
|
}
|
162
169
|
case "eth_sendTransaction": {
|
163
170
|
const transactions = (0, util_1.metaTransactionsFromRequest)(params);
|
@@ -170,15 +177,10 @@ class TransactionManager {
|
|
170
177
|
return {
|
171
178
|
payload: (0, near_ca_1.toPayload)(opHash),
|
172
179
|
evmMessage: JSON.stringify(userOp),
|
173
|
-
|
174
|
-
type: method,
|
175
|
-
// TODO: Double check that this is sufficient for UI.
|
176
|
-
// We may want to adapt and return the `MetaTransactions` instead.
|
177
|
-
data: opHash,
|
178
|
-
},
|
180
|
+
hash: await this.opHash(userOp),
|
179
181
|
};
|
180
182
|
}
|
181
183
|
}
|
182
184
|
}
|
183
185
|
}
|
184
|
-
exports.
|
186
|
+
exports.NearSafe = NearSafe;
|
@@ -1,4 +1,16 @@
|
|
1
|
-
import {
|
1
|
+
import { FunctionCallTransaction, SignArgs } from "near-ca";
|
2
|
+
import { Address, Hash, Hex, ParseAbi, TransactionSerializable } from "viem";
|
3
|
+
export type SafeDeployments = {
|
4
|
+
singleton: Deployment;
|
5
|
+
proxyFactory: Deployment;
|
6
|
+
moduleSetup: Deployment;
|
7
|
+
m4337: Deployment;
|
8
|
+
entryPoint: Deployment;
|
9
|
+
};
|
10
|
+
export interface Deployment {
|
11
|
+
abi: unknown[] | ParseAbi<readonly string[]>;
|
12
|
+
address: Address;
|
13
|
+
}
|
2
14
|
export interface UnsignedUserOperation {
|
3
15
|
sender: Address;
|
4
16
|
nonce: string;
|
@@ -89,4 +101,14 @@ export interface MetaTransaction {
|
|
89
101
|
readonly data: string;
|
90
102
|
readonly operation?: OperationType;
|
91
103
|
}
|
104
|
+
export interface EncodedTxData {
|
105
|
+
evmData: {
|
106
|
+
chainId: number;
|
107
|
+
data: string | TransactionSerializable;
|
108
|
+
hash: Hash;
|
109
|
+
};
|
110
|
+
nearPayload: FunctionCallTransaction<{
|
111
|
+
request: SignArgs;
|
112
|
+
}>;
|
113
|
+
}
|
92
114
|
export {};
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { Deployment, SafeDeployments } from "../src/types";
|
2
|
+
export declare const SAFE_VERSION = "1.4.1";
|
3
|
+
export declare const MODULE_VERSION = "0.3.0";
|
4
|
+
type DeploymentFn = (filter?: {
|
5
|
+
version: string;
|
6
|
+
}) => {
|
7
|
+
networkAddresses: {
|
8
|
+
[chainId: string]: string;
|
9
|
+
};
|
10
|
+
abi: unknown[];
|
11
|
+
} | undefined;
|
12
|
+
type DeploymentArgs = {
|
13
|
+
version: string;
|
14
|
+
};
|
15
|
+
export declare function getDeployment(fn: DeploymentFn, { version }: DeploymentArgs): Promise<Deployment>;
|
16
|
+
export declare function fetchDeployments(safeVersion?: string, moduleVersion?: string): Promise<SafeDeployments>;
|
17
|
+
export {};
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import { getProxyFactoryDeployment, getSafeL2SingletonDeployment, } from "@safe-global/safe-deployments";
|
2
|
+
import { getSafe4337ModuleDeployment, getSafeModuleSetupDeployment, } from "@safe-global/safe-modules-deployments";
|
3
|
+
import { parseAbi } from "viem";
|
4
|
+
import { getClient } from "../src/util";
|
5
|
+
// Define the deployment version and chain ID (e.g., "1.4.1" for Safe contracts, "0.3.0" for modules)
|
6
|
+
export const SAFE_VERSION = "1.4.1";
|
7
|
+
export const MODULE_VERSION = "0.3.0";
|
8
|
+
export async function getDeployment(fn, { version }) {
|
9
|
+
const deployment = fn({ version });
|
10
|
+
if (!deployment) {
|
11
|
+
throw new Error(`Deployment not found for ${fn.name} version ${version}`);
|
12
|
+
}
|
13
|
+
// TODO: maybe call parseAbi on deployment.abi here.
|
14
|
+
return {
|
15
|
+
address: deployment.networkAddresses["11155111"],
|
16
|
+
abi: deployment.abi,
|
17
|
+
};
|
18
|
+
}
|
19
|
+
export async function fetchDeployments(safeVersion = SAFE_VERSION, moduleVersion = MODULE_VERSION) {
|
20
|
+
console.log("Fetching deployments...");
|
21
|
+
const safeDeployment = async (fn) => getDeployment(fn, { version: safeVersion });
|
22
|
+
const m4337Deployment = async (fn) => getDeployment(fn, { version: moduleVersion });
|
23
|
+
try {
|
24
|
+
// Fetch deployments for Safe and 4337 modules
|
25
|
+
const [singleton, proxyFactory, moduleSetup, m4337] = await Promise.all([
|
26
|
+
safeDeployment(getSafeL2SingletonDeployment),
|
27
|
+
safeDeployment(getProxyFactoryDeployment),
|
28
|
+
m4337Deployment(getSafeModuleSetupDeployment),
|
29
|
+
m4337Deployment(getSafe4337ModuleDeployment),
|
30
|
+
]);
|
31
|
+
// TODO - this is a cheeky hack.
|
32
|
+
const client = getClient(11155111);
|
33
|
+
const entryPoint = {
|
34
|
+
address: (await client.readContract({
|
35
|
+
address: m4337.address,
|
36
|
+
abi: m4337.abi,
|
37
|
+
functionName: "SUPPORTED_ENTRYPOINT",
|
38
|
+
})),
|
39
|
+
abi: parseAbi([
|
40
|
+
"function getNonce(address, uint192 key) view returns (uint256 nonce)",
|
41
|
+
]),
|
42
|
+
};
|
43
|
+
return {
|
44
|
+
singleton,
|
45
|
+
proxyFactory,
|
46
|
+
moduleSetup,
|
47
|
+
m4337,
|
48
|
+
entryPoint,
|
49
|
+
};
|
50
|
+
}
|
51
|
+
catch (error) {
|
52
|
+
throw new Error(`Error fetching deployments: ${error}`);
|
53
|
+
}
|
54
|
+
}
|