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
@@ -65,18 +65,19 @@ async function handleRequest(clientMethod) {
|
|
65
65
|
return await clientMethod();
|
66
66
|
}
|
67
67
|
catch (error) {
|
68
|
+
const message = stripApiKey(error);
|
68
69
|
if (error instanceof HttpRequestError) {
|
69
70
|
if (error.status === 401) {
|
70
|
-
throw new Error("Unauthorized request. Please check your API key.");
|
71
|
+
throw new Error("Unauthorized request. Please check your Pimlico API key.");
|
71
72
|
}
|
72
73
|
else {
|
73
|
-
|
74
|
+
throw new Error(`Pimlico: ${message}`);
|
74
75
|
}
|
75
76
|
}
|
76
77
|
else if (error instanceof RpcError) {
|
77
|
-
throw new Error(`Failed to send user op with: ${
|
78
|
+
throw new Error(`Failed to send user op with: ${message}`);
|
78
79
|
}
|
79
|
-
throw new Error(`
|
80
|
+
throw new Error(`Bundler Request: ${message}`);
|
80
81
|
}
|
81
82
|
}
|
82
83
|
// TODO(bh2smith) Should probably get reasonable estimates here:
|
@@ -87,3 +88,12 @@ const defaultPaymasterData = (safeNotDeployed) => {
|
|
87
88
|
preVerificationGas: toHex(100000),
|
88
89
|
};
|
89
90
|
};
|
91
|
+
export function stripApiKey(error) {
|
92
|
+
const message = error instanceof Error ? error.message : String(error);
|
93
|
+
return message.replace(/(apikey=)[^\s&]+/, "$1***");
|
94
|
+
// Could also do this with slicing.
|
95
|
+
// const keyStart = message.indexOf("apikey=") + 7;
|
96
|
+
// // If no apikey in the message, return it as is.
|
97
|
+
// if (keyStart === -1) return message;
|
98
|
+
// return `${message.slice(0, keyStart)}***${message.slice(keyStart + 36)}`;
|
99
|
+
}
|
@@ -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,4 +1,3 @@
|
|
1
|
-
import { toPayload } from "near-ca";
|
2
1
|
import { gte } from "semver";
|
3
2
|
import { fromHex, hashMessage, hashTypedData, isHex, } from "viem";
|
4
3
|
/*
|
@@ -80,21 +79,6 @@ export function decodeSafeMessage(message, safe) {
|
|
80
79
|
safeMessageHash: generateSafeMessageHash(safe, decodedMessage),
|
81
80
|
};
|
82
81
|
}
|
83
|
-
export function safeMessageTxData(method, message, sender) {
|
84
|
-
return {
|
85
|
-
evmMessage: message.safeMessageMessage,
|
86
|
-
payload: toPayload(message.safeMessageHash),
|
87
|
-
recoveryData: {
|
88
|
-
type: method,
|
89
|
-
data: {
|
90
|
-
address: sender,
|
91
|
-
// TODO - Upgrade Signable Message in near-ca
|
92
|
-
// @ts-expect-error: Type 'string | EIP712TypedData' is not assignable to type 'SignableMessage'.
|
93
|
-
message: decodedMessage,
|
94
|
-
},
|
95
|
-
},
|
96
|
-
};
|
97
|
-
}
|
98
82
|
// const isEIP712TypedData = (obj: any): obj is EIP712TypedData => {
|
99
83
|
// return (
|
100
84
|
// 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,11 +1,10 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
import { encodeFunctionData, encodePacked, getCreate2Address, keccak256, parseAbi, toHex, zeroAddress, } from "viem";
|
1
|
+
import { encodeFunctionData, encodePacked, getCreate2Address, keccak256, toHex, zeroAddress, } from "viem";
|
2
|
+
import { SAFE_DEPLOYMENTS } from "../_gen/deployments";
|
4
3
|
import { PLACEHOLDER_SIG, getClient, packGas, packPaymasterData, } from "../util";
|
5
4
|
/**
|
6
5
|
* All contracts used in account creation & execution
|
7
6
|
*/
|
8
|
-
export class
|
7
|
+
export class SafeContractSuite {
|
9
8
|
// Used only for stateless contract reads.
|
10
9
|
dummyClient;
|
11
10
|
singleton;
|
@@ -13,46 +12,14 @@ export class ContractSuite {
|
|
13
12
|
m4337;
|
14
13
|
moduleSetup;
|
15
14
|
entryPoint;
|
16
|
-
constructor(
|
17
|
-
this.dummyClient =
|
18
|
-
|
19
|
-
this.
|
20
|
-
this.
|
21
|
-
this.
|
22
|
-
this.
|
23
|
-
|
24
|
-
static async init() {
|
25
|
-
// TODO - this is a cheeky hack.
|
26
|
-
const client = getClient(11155111);
|
27
|
-
const safeDeployment = (fn) => getDeployment(fn, { version: "1.4.1" });
|
28
|
-
const m4337Deployment = async (fn) => {
|
29
|
-
return getDeployment(fn, { version: "0.3.0" });
|
30
|
-
};
|
31
|
-
const [singleton, proxyFactory, moduleSetup, m4337] = await Promise.all([
|
32
|
-
safeDeployment(getSafeL2SingletonDeployment),
|
33
|
-
safeDeployment(getProxyFactoryDeployment),
|
34
|
-
m4337Deployment(getSafeModuleSetupDeployment),
|
35
|
-
m4337Deployment(getSafe4337ModuleDeployment),
|
36
|
-
]);
|
37
|
-
// console.log("Initialized ERC4337 & Safe Module Contracts:", {
|
38
|
-
// singleton: await singleton.getAddress(),
|
39
|
-
// proxyFactory: await proxyFactory.getAddress(),
|
40
|
-
// m4337: await m4337.getAddress(),
|
41
|
-
// moduleSetup: await moduleSetup.getAddress(),
|
42
|
-
// entryPoint: await entryPoint.getAddress(),
|
43
|
-
// });
|
44
|
-
return new ContractSuite(client, singleton, proxyFactory, m4337, moduleSetup,
|
45
|
-
// EntryPoint:
|
46
|
-
{
|
47
|
-
address: (await client.readContract({
|
48
|
-
address: m4337.address,
|
49
|
-
abi: m4337.abi,
|
50
|
-
functionName: "SUPPORTED_ENTRYPOINT",
|
51
|
-
})),
|
52
|
-
abi: parseAbi([
|
53
|
-
"function getNonce(address, uint192 key) view returns (uint256 nonce)",
|
54
|
-
]),
|
55
|
-
});
|
15
|
+
constructor() {
|
16
|
+
this.dummyClient = getClient(11155111);
|
17
|
+
const deployments = SAFE_DEPLOYMENTS;
|
18
|
+
this.singleton = deployments.singleton;
|
19
|
+
this.proxyFactory = deployments.proxyFactory;
|
20
|
+
this.m4337 = deployments.m4337;
|
21
|
+
this.moduleSetup = deployments.moduleSetup;
|
22
|
+
this.entryPoint = deployments.entryPoint;
|
56
23
|
}
|
57
24
|
async addressForSetup(setup, saltNonce) {
|
58
25
|
// bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce));
|
@@ -163,14 +130,3 @@ export class ContractSuite {
|
|
163
130
|
return nonce;
|
164
131
|
}
|
165
132
|
}
|
166
|
-
async function getDeployment(fn, { version }) {
|
167
|
-
const deployment = fn({ version });
|
168
|
-
if (!deployment) {
|
169
|
-
throw new Error(`Deployment not found for ${fn.name} version ${version}`);
|
170
|
-
}
|
171
|
-
// TODO: maybe call parseAbi on deployment.abi here.
|
172
|
-
return {
|
173
|
-
address: deployment.networkAddresses["11155111"],
|
174
|
-
abi: deployment.abi,
|
175
|
-
};
|
176
|
-
}
|
@@ -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
|
}
|
@@ -2,37 +2,37 @@ import { setupAdapter, signatureFromOutcome, toPayload, } from "near-ca";
|
|
2
2
|
import { serializeSignature } from "viem";
|
3
3
|
import { Erc4337Bundler } from "./lib/bundler";
|
4
4
|
import { encodeMulti } from "./lib/multisend";
|
5
|
-
import {
|
6
|
-
import { decodeSafeMessage
|
5
|
+
import { SafeContractSuite } from "./lib/safe";
|
6
|
+
import { decodeSafeMessage } from "./lib/safe-message";
|
7
7
|
import { getClient, isContract, metaTransactionsFromRequest, packSignature, } from "./util";
|
8
|
-
export class
|
8
|
+
export class NearSafe {
|
9
9
|
nearAdapter;
|
10
10
|
address;
|
11
11
|
safePack;
|
12
12
|
setup;
|
13
13
|
pimlicoKey;
|
14
14
|
safeSaltNonce;
|
15
|
-
|
15
|
+
static async create(config) {
|
16
|
+
const { pimlicoKey, safeSaltNonce } = config;
|
17
|
+
const nearAdapter = await setupAdapter({ ...config });
|
18
|
+
const safePack = new SafeContractSuite();
|
19
|
+
const setup = safePack.getSetup([nearAdapter.address]);
|
20
|
+
const safeAddress = await safePack.addressForSetup(setup, safeSaltNonce);
|
21
|
+
console.log(`
|
22
|
+
Near Adapter:
|
23
|
+
Near Account ID: ${nearAdapter.nearAccountId()}
|
24
|
+
MPC EOA: ${nearAdapter.address}
|
25
|
+
Safe: ${safeAddress}
|
26
|
+
`);
|
27
|
+
return new NearSafe(nearAdapter, safePack, pimlicoKey, setup, safeAddress, safeSaltNonce || "0");
|
28
|
+
}
|
16
29
|
constructor(nearAdapter, safePack, pimlicoKey, setup, safeAddress, safeSaltNonce) {
|
17
30
|
this.nearAdapter = nearAdapter;
|
31
|
+
this.address = safeAddress;
|
32
|
+
this.setup = setup;
|
18
33
|
this.safePack = safePack;
|
19
34
|
this.pimlicoKey = pimlicoKey;
|
20
|
-
this.setup = setup;
|
21
|
-
this.address = safeAddress;
|
22
35
|
this.safeSaltNonce = safeSaltNonce;
|
23
|
-
this.deployedChains = new Set();
|
24
|
-
}
|
25
|
-
static async create(config) {
|
26
|
-
const { pimlicoKey } = config;
|
27
|
-
const [nearAdapter, safePack] = await Promise.all([
|
28
|
-
setupAdapter({ ...config }),
|
29
|
-
ContractSuite.init(),
|
30
|
-
]);
|
31
|
-
console.log(`Near Adapter: ${nearAdapter.nearAccountId()} <> ${nearAdapter.address}`);
|
32
|
-
const setup = safePack.getSetup([nearAdapter.address]);
|
33
|
-
const safeAddress = await safePack.addressForSetup(setup, config.safeSaltNonce);
|
34
|
-
console.log(`Safe Address: ${safeAddress}`);
|
35
|
-
return new TransactionManager(nearAdapter, safePack, pimlicoKey, setup, safeAddress, config.safeSaltNonce || "0");
|
36
36
|
}
|
37
37
|
get mpcAddress() {
|
38
38
|
return this.nearAdapter.address;
|
@@ -43,9 +43,6 @@ export class TransactionManager {
|
|
43
43
|
async getBalance(chainId) {
|
44
44
|
return await getClient(chainId).getBalance({ address: this.address });
|
45
45
|
}
|
46
|
-
bundlerForChainId(chainId) {
|
47
|
-
return new Erc4337Bundler(this.safePack.entryPoint.address, this.pimlicoKey, chainId);
|
48
|
-
}
|
49
46
|
async buildTransaction(args) {
|
50
47
|
const { transactions, usePaymaster, chainId } = args;
|
51
48
|
if (transactions.length === 0) {
|
@@ -72,16 +69,35 @@ export class TransactionManager {
|
|
72
69
|
return this.safePack.getOpHash(userOp);
|
73
70
|
}
|
74
71
|
async encodeSignRequest(signRequest, usePaymaster) {
|
75
|
-
const
|
72
|
+
const { payload, evmMessage, hash } = await this.requestRouter(signRequest, usePaymaster);
|
76
73
|
return {
|
77
74
|
nearPayload: await this.nearAdapter.mpcContract.encodeSignatureRequestTx({
|
78
75
|
path: this.nearAdapter.derivationPath,
|
79
|
-
payload
|
76
|
+
payload,
|
80
77
|
key_version: 0,
|
81
78
|
}),
|
82
|
-
|
79
|
+
evmData: {
|
80
|
+
chainId: signRequest.chainId,
|
81
|
+
data: evmMessage,
|
82
|
+
hash,
|
83
|
+
},
|
83
84
|
};
|
84
85
|
}
|
86
|
+
async broadcastEvm(chainId, outcome, unsignedUserOp) {
|
87
|
+
const signature = packSignature(serializeSignature(signatureFromOutcome(outcome)));
|
88
|
+
try {
|
89
|
+
return {
|
90
|
+
signature,
|
91
|
+
receipt: await this.executeTransaction(chainId, {
|
92
|
+
...unsignedUserOp,
|
93
|
+
signature,
|
94
|
+
}),
|
95
|
+
};
|
96
|
+
}
|
97
|
+
catch (error) {
|
98
|
+
throw new Error(`Failed EVM broadcast: ${error instanceof Error ? error.message : String(error)}`);
|
99
|
+
}
|
100
|
+
}
|
85
101
|
async executeTransaction(chainId, userOp) {
|
86
102
|
const bundler = this.bundlerForChainId(chainId);
|
87
103
|
const userOpHash = await bundler.sendUserOperation(userOp);
|
@@ -93,15 +109,15 @@ export class TransactionManager {
|
|
93
109
|
return userOpReceipt;
|
94
110
|
}
|
95
111
|
async safeDeployed(chainId) {
|
96
|
-
|
97
|
-
|
112
|
+
return isContract(this.address, chainId);
|
113
|
+
}
|
114
|
+
async sufficientlyFunded(chainId, transactions, gasCost) {
|
115
|
+
const txValue = transactions.reduce((acc, tx) => acc + BigInt(tx.value), 0n);
|
116
|
+
if (txValue + gasCost === 0n) {
|
98
117
|
return true;
|
99
118
|
}
|
100
|
-
const
|
101
|
-
|
102
|
-
this.deployedChains.add(chainId);
|
103
|
-
}
|
104
|
-
return deployed;
|
119
|
+
const safeBalance = await this.getBalance(chainId);
|
120
|
+
return txValue + gasCost < safeBalance;
|
105
121
|
}
|
106
122
|
addOwnerTx(address) {
|
107
123
|
return {
|
@@ -110,28 +126,8 @@ export class TransactionManager {
|
|
110
126
|
data: this.safePack.addOwnerData(address),
|
111
127
|
};
|
112
128
|
}
|
113
|
-
|
114
|
-
|
115
|
-
if (txValue + gasCost === 0n) {
|
116
|
-
return true;
|
117
|
-
}
|
118
|
-
const safeBalance = await this.getBalance(chainId);
|
119
|
-
return txValue + gasCost < safeBalance;
|
120
|
-
}
|
121
|
-
async broadcastEvm(chainId, outcome, unsignedUserOp) {
|
122
|
-
const signature = packSignature(serializeSignature(signatureFromOutcome(outcome)));
|
123
|
-
try {
|
124
|
-
return {
|
125
|
-
signature,
|
126
|
-
receipt: await this.executeTransaction(chainId, {
|
127
|
-
...unsignedUserOp,
|
128
|
-
signature,
|
129
|
-
}),
|
130
|
-
};
|
131
|
-
}
|
132
|
-
catch (error) {
|
133
|
-
throw new Error(`Failed EVM broadcast: ${error instanceof Error ? error.message : String(error)}`);
|
134
|
-
}
|
129
|
+
bundlerForChainId(chainId) {
|
130
|
+
return new Erc4337Bundler(this.safePack.entryPoint.address, this.pimlicoKey, chainId);
|
135
131
|
}
|
136
132
|
/**
|
137
133
|
* Handles routing of signature requests based on the provided method, chain ID, and parameters.
|
@@ -156,12 +152,22 @@ export class TransactionManager {
|
|
156
152
|
case "eth_signTypedData":
|
157
153
|
case "eth_signTypedData_v4":
|
158
154
|
case "eth_sign": {
|
159
|
-
const [
|
160
|
-
|
155
|
+
const [_, messageOrData] = params;
|
156
|
+
const message = decodeSafeMessage(messageOrData, safeInfo);
|
157
|
+
return {
|
158
|
+
evmMessage: message.safeMessageMessage,
|
159
|
+
payload: toPayload(message.safeMessageHash),
|
160
|
+
hash: message.safeMessageHash,
|
161
|
+
};
|
161
162
|
}
|
162
163
|
case "personal_sign": {
|
163
|
-
const [messageHash,
|
164
|
-
|
164
|
+
const [messageHash, _] = params;
|
165
|
+
const message = decodeSafeMessage(messageHash, safeInfo);
|
166
|
+
return {
|
167
|
+
evmMessage: message.safeMessageMessage,
|
168
|
+
payload: toPayload(message.safeMessageHash),
|
169
|
+
hash: message.safeMessageHash,
|
170
|
+
};
|
165
171
|
}
|
166
172
|
case "eth_sendTransaction": {
|
167
173
|
const transactions = metaTransactionsFromRequest(params);
|
@@ -174,12 +180,7 @@ export class TransactionManager {
|
|
174
180
|
return {
|
175
181
|
payload: toPayload(opHash),
|
176
182
|
evmMessage: JSON.stringify(userOp),
|
177
|
-
|
178
|
-
type: method,
|
179
|
-
// TODO: Double check that this is sufficient for UI.
|
180
|
-
// We may want to adapt and return the `MetaTransactions` instead.
|
181
|
-
data: opHash,
|
182
|
-
},
|
183
|
+
hash: await this.opHash(userOp),
|
183
184
|
};
|
184
185
|
}
|
185
186
|
}
|
@@ -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 {};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "near-safe",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.0",
|
4
4
|
"license": "MIT",
|
5
5
|
"description": "An SDK for controlling Ethereum Smart Accounts via ERC4337 from a Near Account.",
|
6
6
|
"author": "bh2smith",
|
@@ -32,6 +32,7 @@
|
|
32
32
|
"build": "rm -fr dist/* && yarn build:esm && yarn build:cjs",
|
33
33
|
"build:esm": "tsc -p tsconfig.esm.json",
|
34
34
|
"build:cjs": "tsc -p tsconfig.cjs.json",
|
35
|
+
"build:deployments": "tsx scripts/safe-deployments.ts && prettier --write 'src/_gen/**/*.ts'",
|
35
36
|
"start": "yarn example",
|
36
37
|
"example": "tsx examples/send-tx.ts",
|
37
38
|
"lint": "eslint . --ignore-pattern dist/",
|
@@ -40,15 +41,15 @@
|
|
40
41
|
"all": "yarn fmt && yarn lint && yarn build"
|
41
42
|
},
|
42
43
|
"dependencies": {
|
43
|
-
"@safe-global/safe-deployments": "^1.37.0",
|
44
44
|
"@safe-global/safe-gateway-typescript-sdk": "^3.22.2",
|
45
|
-
"@safe-global/safe-modules-deployments": "^2.2.0",
|
46
45
|
"near-api-js": "^5.0.0",
|
47
46
|
"near-ca": "^0.5.6",
|
48
47
|
"semver": "^7.6.3",
|
49
48
|
"viem": "^2.16.5"
|
50
49
|
},
|
51
50
|
"devDependencies": {
|
51
|
+
"@safe-global/safe-deployments": "^1.37.0",
|
52
|
+
"@safe-global/safe-modules-deployments": "^2.2.0",
|
52
53
|
"@types/jest": "^29.5.12",
|
53
54
|
"@types/node": "^22.3.0",
|
54
55
|
"@types/semver": "^7.5.8",
|
package/dist/cjs/lib/safe.d.ts
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
import { Address, Hash, Hex, ParseAbi, PublicClient } from "viem";
|
2
|
-
import { GasPrice, MetaTransaction, UnsignedUserOperation, UserOperation } from "../types";
|
3
|
-
interface DeploymentData {
|
4
|
-
abi: unknown[] | ParseAbi<readonly string[]>;
|
5
|
-
address: `0x${string}`;
|
6
|
-
}
|
7
|
-
/**
|
8
|
-
* All contracts used in account creation & execution
|
9
|
-
*/
|
10
|
-
export declare class ContractSuite {
|
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);
|
18
|
-
static init(): Promise<ContractSuite>;
|
19
|
-
addressForSetup(setup: Hex, saltNonce?: string): Promise<Address>;
|
20
|
-
getSetup(owners: string[]): Hex;
|
21
|
-
addOwnerData(newOwner: Address): Hex;
|
22
|
-
getOpHash(unsignedUserOp: UserOperation): Promise<Hash>;
|
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>;
|
26
|
-
}
|
27
|
-
export {};
|
package/dist/esm/lib/safe.d.ts
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
import { Address, Hash, Hex, ParseAbi, PublicClient } from "viem";
|
2
|
-
import { GasPrice, MetaTransaction, UnsignedUserOperation, UserOperation } from "../types";
|
3
|
-
interface DeploymentData {
|
4
|
-
abi: unknown[] | ParseAbi<readonly string[]>;
|
5
|
-
address: `0x${string}`;
|
6
|
-
}
|
7
|
-
/**
|
8
|
-
* All contracts used in account creation & execution
|
9
|
-
*/
|
10
|
-
export declare class ContractSuite {
|
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);
|
18
|
-
static init(): Promise<ContractSuite>;
|
19
|
-
addressForSetup(setup: Hex, saltNonce?: string): Promise<Address>;
|
20
|
-
getSetup(owners: string[]): Hex;
|
21
|
-
addOwnerData(newOwner: Address): Hex;
|
22
|
-
getOpHash(unsignedUserOp: UserOperation): Promise<Hash>;
|
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>;
|
26
|
-
}
|
27
|
-
export {};
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|