near-safe 0.0.5 → 0.1.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/README.md CHANGED
@@ -33,7 +33,7 @@ NEAR_ACCOUNT_ID=
33
33
  NEAR_ACCOUNT_PRIVATE_KEY=
34
34
 
35
35
  # Head to https://www.pimlico.io/ for an API key
36
- ERC4337_BUNDLER_URL=
36
+ PIMLICO_KEY=
37
37
  ```
38
38
 
39
39
 
@@ -19,7 +19,15 @@ class ContractSuite {
19
19
  }
20
20
  static async init(provider) {
21
21
  const safeDeployment = (fn) => getDeployment(fn, { provider, version: "1.4.1" });
22
- const m4337Deployment = (fn) => getDeployment(fn, { provider, version: "0.3.0" });
22
+ const m4337Deployment = async (fn) => {
23
+ try {
24
+ return await getDeployment(fn, { provider, version: "0.3.0" });
25
+ }
26
+ catch (error) {
27
+ console.warn(error.message, "using v0.2.0");
28
+ return getDeployment(fn, { provider, version: "0.2.0" });
29
+ }
30
+ };
23
31
  // Need this first to get entryPoint address
24
32
  const m4337 = await m4337Deployment(safe_modules_deployments_1.getSafe4337ModuleDeployment);
25
33
  const [singleton, proxyFactory, moduleSetup, supportedEntryPoint] = await Promise.all([
@@ -29,6 +37,13 @@ class ContractSuite {
29
37
  m4337.SUPPORTED_ENTRYPOINT(),
30
38
  ]);
31
39
  const entryPoint = new ethers_1.ethers.Contract(supportedEntryPoint, ["function getNonce(address, uint192 key) view returns (uint256 nonce)"], provider);
40
+ console.log("Initialized ERC4337 & Safe Module Contracts:", {
41
+ singleton: await singleton.getAddress(),
42
+ proxyFactory: await proxyFactory.getAddress(),
43
+ m4337: await m4337.getAddress(),
44
+ moduleSetup: await moduleSetup.getAddress(),
45
+ entryPoint: await entryPoint.getAddress(),
46
+ });
32
47
  return new ContractSuite(provider, singleton, proxyFactory, m4337, moduleSetup, entryPoint);
33
48
  }
34
49
  async addressForSetup(setup, saltNonce) {
@@ -102,7 +117,7 @@ async function getDeployment(fn, { provider, version }) {
102
117
  const { chainId } = await provider.getNetwork();
103
118
  const deployment = fn({ version });
104
119
  if (!deployment || !deployment.networkAddresses[`${chainId}`]) {
105
- throw new Error(`Deployment not found for version ${version} and chainId ${chainId}`);
120
+ throw new Error(`Deployment not found for ${fn.name} version ${version} on chainId ${chainId}`);
106
121
  }
107
122
  return new ethers_1.ethers.Contract(deployment.networkAddresses[`${chainId}`], deployment.abi, provider);
108
123
  }
@@ -4,26 +4,30 @@ import { Erc4337Bundler } from "./lib/bundler";
4
4
  import { UserOperation, UserOperationReceipt } from "./types";
5
5
  import { MetaTransaction } from "ethers-multisend";
6
6
  import { ContractSuite } from "./lib/safe";
7
- import { Account } from "near-api-js";
8
7
  export declare class TransactionManager {
9
8
  readonly provider: ethers.JsonRpcProvider;
10
9
  readonly nearAdapter: NearEthAdapter;
11
10
  private safePack;
12
11
  private bundler;
13
12
  private setup;
14
- readonly safeAddress: string;
13
+ readonly address: string;
14
+ readonly chainId: number;
15
15
  private safeSaltNonce;
16
16
  private _safeNotDeployed;
17
- constructor(provider: ethers.JsonRpcProvider, nearAdapter: NearEthAdapter, safePack: ContractSuite, bundler: Erc4337Bundler, setup: string, safeAddress: string, safeSaltNonce: string, safeNotDeployed: boolean);
17
+ constructor(provider: ethers.JsonRpcProvider, nearAdapter: NearEthAdapter, safePack: ContractSuite, bundler: Erc4337Bundler, setup: string, chainId: number, safeAddress: string, safeSaltNonce: string, safeNotDeployed: boolean);
18
18
  static create(config: {
19
19
  ethRpc: string;
20
- erc4337BundlerUrl: string;
21
- nearAccount: Account;
22
- mpcContractId: string;
20
+ pimlicoKey: string;
21
+ nearAdapter: NearEthAdapter;
23
22
  safeSaltNonce?: string;
24
23
  }): Promise<TransactionManager>;
24
+ static fromChainId(args: {
25
+ chainId: number;
26
+ nearAdapter: NearEthAdapter;
27
+ pimlicoKey: string;
28
+ }): Promise<TransactionManager>;
25
29
  get safeNotDeployed(): boolean;
26
- get nearEOA(): `0x${string}`;
30
+ get mpcAddress(): `0x${string}`;
27
31
  getSafeBalance(): Promise<bigint>;
28
32
  buildTransaction(args: {
29
33
  transactions: MetaTransaction[];
@@ -9,40 +9,46 @@ const near_1 = require("./lib/near");
9
9
  const ethers_multisend_1 = require("ethers-multisend");
10
10
  const safe_1 = require("./lib/safe");
11
11
  class TransactionManager {
12
- constructor(provider, nearAdapter, safePack, bundler, setup, safeAddress, safeSaltNonce, safeNotDeployed) {
12
+ constructor(provider, nearAdapter, safePack, bundler, setup, chainId, safeAddress, safeSaltNonce, safeNotDeployed) {
13
13
  this.provider = provider;
14
14
  this.nearAdapter = nearAdapter;
15
15
  this.safePack = safePack;
16
16
  this.bundler = bundler;
17
17
  this.setup = setup;
18
- this.safeAddress = safeAddress;
18
+ this.chainId = chainId;
19
+ this.address = safeAddress;
19
20
  this.safeSaltNonce = safeSaltNonce;
20
21
  this._safeNotDeployed = safeNotDeployed;
21
22
  }
22
23
  static async create(config) {
24
+ const { nearAdapter, pimlicoKey } = config;
23
25
  const provider = new ethers_1.ethers.JsonRpcProvider(config.ethRpc);
24
- const [nearAdapter, safePack] = await Promise.all([
25
- near_ca_1.NearEthAdapter.fromConfig({
26
- mpcContract: new near_ca_1.MpcContract(config.nearAccount, config.mpcContractId),
27
- }),
28
- safe_1.ContractSuite.init(provider),
29
- ]);
26
+ const chainId = (await provider.getNetwork()).chainId;
27
+ const safePack = await safe_1.ContractSuite.init(provider);
30
28
  console.log(`Near Adapter: ${nearAdapter.nearAccountId()} <> ${nearAdapter.address}`);
31
- const bundler = new bundler_1.Erc4337Bundler(config.erc4337BundlerUrl, await safePack.entryPoint.getAddress());
29
+ const bundler = new bundler_1.Erc4337Bundler(`https://api.pimlico.io/v2/${chainId}/rpc?apikey=${pimlicoKey}`, await safePack.entryPoint.getAddress());
32
30
  const setup = await safePack.getSetup([nearAdapter.address]);
33
31
  const safeAddress = await safePack.addressForSetup(setup, config.safeSaltNonce);
34
32
  const safeNotDeployed = (await provider.getCode(safeAddress)) === "0x";
35
33
  console.log(`Safe Address: ${safeAddress} - deployed? ${!safeNotDeployed}`);
36
- return new TransactionManager(provider, nearAdapter, safePack, bundler, setup, safeAddress, config.safeSaltNonce || "0", safeNotDeployed);
34
+ return new TransactionManager(provider, nearAdapter, safePack, bundler, setup, parseInt(chainId.toString()), safeAddress, config.safeSaltNonce || "0", safeNotDeployed);
35
+ }
36
+ static async fromChainId(args) {
37
+ const { pimlicoKey, nearAdapter } = args;
38
+ return TransactionManager.create({
39
+ ethRpc: near_ca_1.Network.fromChainId(args.chainId).rpcUrl,
40
+ pimlicoKey,
41
+ nearAdapter,
42
+ });
37
43
  }
38
44
  get safeNotDeployed() {
39
45
  return this._safeNotDeployed;
40
46
  }
41
- get nearEOA() {
47
+ get mpcAddress() {
42
48
  return this.nearAdapter.address;
43
49
  }
44
50
  async getSafeBalance() {
45
- return await this.provider.getBalance(this.safeAddress);
51
+ return await this.provider.getBalance(this.address);
46
52
  }
47
53
  async buildTransaction(args) {
48
54
  const { transactions, usePaymaster } = args;
@@ -53,7 +59,7 @@ class TransactionManager {
53
59
  throw new Error("Empty transaction set!");
54
60
  }
55
61
  const tx = transactions.length > 1 ? (0, ethers_multisend_1.encodeMulti)(transactions) : transactions[0];
56
- const rawUserOp = await this.safePack.buildUserOp(tx, this.safeAddress, gasFees, this.setup, this.safeNotDeployed, this.safeSaltNonce);
62
+ const rawUserOp = await this.safePack.buildUserOp(tx, this.address, gasFees, this.setup, this.safeNotDeployed, this.safeSaltNonce);
57
63
  const paymasterData = await this.bundler.getPaymasterData(rawUserOp, usePaymaster, this.safeNotDeployed);
58
64
  const unsignedUserOp = { ...rawUserOp, ...paymasterData };
59
65
  return unsignedUserOp;
@@ -67,6 +73,9 @@ class TransactionManager {
67
73
  }
68
74
  async encodeSignRequest(tx) {
69
75
  // TODO - This is sloppy and ignores ChainId!
76
+ if (tx.chainId !== this.chainId) {
77
+ throw new Error(`Transaciton request for invalid ChainId ${tx.chainId} != ${this.chainId}`);
78
+ }
70
79
  const unsignedUserOp = await this.buildTransaction({
71
80
  transactions: [
72
81
  {
@@ -95,12 +104,12 @@ class TransactionManager {
95
104
  console.log("userOp Receipt", userOpReceipt);
96
105
  // Update safeNotDeployed after the first transaction
97
106
  this._safeNotDeployed =
98
- (await this.provider.getCode(this.safeAddress)) === "0x";
107
+ (await this.provider.getCode(this.address)) === "0x";
99
108
  return userOpReceipt;
100
109
  }
101
110
  addOwnerTx(address) {
102
111
  return {
103
- to: this.safeAddress,
112
+ to: this.address,
104
113
  value: "0",
105
114
  data: this.safePack.singleton.interface.encodeFunctionData("addOwnerWithThreshold", [address, 1]),
106
115
  };
@@ -22,7 +22,15 @@ export class ContractSuite {
22
22
  }
23
23
  static async init(provider) {
24
24
  const safeDeployment = (fn) => getDeployment(fn, { provider, version: "1.4.1" });
25
- const m4337Deployment = (fn) => getDeployment(fn, { provider, version: "0.3.0" });
25
+ const m4337Deployment = async (fn) => {
26
+ try {
27
+ return await getDeployment(fn, { provider, version: "0.3.0" });
28
+ }
29
+ catch (error) {
30
+ console.warn(error.message, "using v0.2.0");
31
+ return getDeployment(fn, { provider, version: "0.2.0" });
32
+ }
33
+ };
26
34
  // Need this first to get entryPoint address
27
35
  const m4337 = await m4337Deployment(getSafe4337ModuleDeployment);
28
36
  const [singleton, proxyFactory, moduleSetup, supportedEntryPoint] = await Promise.all([
@@ -32,6 +40,13 @@ export class ContractSuite {
32
40
  m4337.SUPPORTED_ENTRYPOINT(),
33
41
  ]);
34
42
  const entryPoint = new ethers.Contract(supportedEntryPoint, ["function getNonce(address, uint192 key) view returns (uint256 nonce)"], provider);
43
+ console.log("Initialized ERC4337 & Safe Module Contracts:", {
44
+ singleton: await singleton.getAddress(),
45
+ proxyFactory: await proxyFactory.getAddress(),
46
+ m4337: await m4337.getAddress(),
47
+ moduleSetup: await moduleSetup.getAddress(),
48
+ entryPoint: await entryPoint.getAddress(),
49
+ });
35
50
  return new ContractSuite(provider, singleton, proxyFactory, m4337, moduleSetup, entryPoint);
36
51
  }
37
52
  async addressForSetup(setup, saltNonce) {
@@ -104,7 +119,7 @@ async function getDeployment(fn, { provider, version }) {
104
119
  const { chainId } = await provider.getNetwork();
105
120
  const deployment = fn({ version });
106
121
  if (!deployment || !deployment.networkAddresses[`${chainId}`]) {
107
- throw new Error(`Deployment not found for version ${version} and chainId ${chainId}`);
122
+ throw new Error(`Deployment not found for ${fn.name} version ${version} on chainId ${chainId}`);
108
123
  }
109
124
  return new ethers.Contract(deployment.networkAddresses[`${chainId}`], deployment.abi, provider);
110
125
  }
@@ -4,26 +4,30 @@ import { Erc4337Bundler } from "./lib/bundler";
4
4
  import { UserOperation, UserOperationReceipt } from "./types";
5
5
  import { MetaTransaction } from "ethers-multisend";
6
6
  import { ContractSuite } from "./lib/safe";
7
- import { Account } from "near-api-js";
8
7
  export declare class TransactionManager {
9
8
  readonly provider: ethers.JsonRpcProvider;
10
9
  readonly nearAdapter: NearEthAdapter;
11
10
  private safePack;
12
11
  private bundler;
13
12
  private setup;
14
- readonly safeAddress: string;
13
+ readonly address: string;
14
+ readonly chainId: number;
15
15
  private safeSaltNonce;
16
16
  private _safeNotDeployed;
17
- constructor(provider: ethers.JsonRpcProvider, nearAdapter: NearEthAdapter, safePack: ContractSuite, bundler: Erc4337Bundler, setup: string, safeAddress: string, safeSaltNonce: string, safeNotDeployed: boolean);
17
+ constructor(provider: ethers.JsonRpcProvider, nearAdapter: NearEthAdapter, safePack: ContractSuite, bundler: Erc4337Bundler, setup: string, chainId: number, safeAddress: string, safeSaltNonce: string, safeNotDeployed: boolean);
18
18
  static create(config: {
19
19
  ethRpc: string;
20
- erc4337BundlerUrl: string;
21
- nearAccount: Account;
22
- mpcContractId: string;
20
+ pimlicoKey: string;
21
+ nearAdapter: NearEthAdapter;
23
22
  safeSaltNonce?: string;
24
23
  }): Promise<TransactionManager>;
24
+ static fromChainId(args: {
25
+ chainId: number;
26
+ nearAdapter: NearEthAdapter;
27
+ pimlicoKey: string;
28
+ }): Promise<TransactionManager>;
25
29
  get safeNotDeployed(): boolean;
26
- get nearEOA(): `0x${string}`;
30
+ get mpcAddress(): `0x${string}`;
27
31
  getSafeBalance(): Promise<bigint>;
28
32
  buildTransaction(args: {
29
33
  transactions: MetaTransaction[];
@@ -1,5 +1,5 @@
1
1
  import { ethers } from "ethers";
2
- import { NearEthAdapter, MpcContract } from "near-ca";
2
+ import { Network } from "near-ca";
3
3
  import { Erc4337Bundler } from "./lib/bundler";
4
4
  import { packSignature } from "./util";
5
5
  import { getNearSignature } from "./lib/near";
@@ -11,43 +11,50 @@ export class TransactionManager {
11
11
  safePack;
12
12
  bundler;
13
13
  setup;
14
- safeAddress;
14
+ address;
15
+ chainId;
15
16
  safeSaltNonce;
16
17
  _safeNotDeployed;
17
- constructor(provider, nearAdapter, safePack, bundler, setup, safeAddress, safeSaltNonce, safeNotDeployed) {
18
+ constructor(provider, nearAdapter, safePack, bundler, setup, chainId, safeAddress, safeSaltNonce, safeNotDeployed) {
18
19
  this.provider = provider;
19
20
  this.nearAdapter = nearAdapter;
20
21
  this.safePack = safePack;
21
22
  this.bundler = bundler;
22
23
  this.setup = setup;
23
- this.safeAddress = safeAddress;
24
+ this.chainId = chainId;
25
+ this.address = safeAddress;
24
26
  this.safeSaltNonce = safeSaltNonce;
25
27
  this._safeNotDeployed = safeNotDeployed;
26
28
  }
27
29
  static async create(config) {
30
+ const { nearAdapter, pimlicoKey } = config;
28
31
  const provider = new ethers.JsonRpcProvider(config.ethRpc);
29
- const [nearAdapter, safePack] = await Promise.all([
30
- NearEthAdapter.fromConfig({
31
- mpcContract: new MpcContract(config.nearAccount, config.mpcContractId),
32
- }),
33
- ContractSuite.init(provider),
34
- ]);
32
+ const chainId = (await provider.getNetwork()).chainId;
33
+ const safePack = await ContractSuite.init(provider);
35
34
  console.log(`Near Adapter: ${nearAdapter.nearAccountId()} <> ${nearAdapter.address}`);
36
- const bundler = new Erc4337Bundler(config.erc4337BundlerUrl, await safePack.entryPoint.getAddress());
35
+ const bundler = new Erc4337Bundler(`https://api.pimlico.io/v2/${chainId}/rpc?apikey=${pimlicoKey}`, await safePack.entryPoint.getAddress());
37
36
  const setup = await safePack.getSetup([nearAdapter.address]);
38
37
  const safeAddress = await safePack.addressForSetup(setup, config.safeSaltNonce);
39
38
  const safeNotDeployed = (await provider.getCode(safeAddress)) === "0x";
40
39
  console.log(`Safe Address: ${safeAddress} - deployed? ${!safeNotDeployed}`);
41
- return new TransactionManager(provider, nearAdapter, safePack, bundler, setup, safeAddress, config.safeSaltNonce || "0", safeNotDeployed);
40
+ return new TransactionManager(provider, nearAdapter, safePack, bundler, setup, parseInt(chainId.toString()), safeAddress, config.safeSaltNonce || "0", safeNotDeployed);
41
+ }
42
+ static async fromChainId(args) {
43
+ const { pimlicoKey, nearAdapter } = args;
44
+ return TransactionManager.create({
45
+ ethRpc: Network.fromChainId(args.chainId).rpcUrl,
46
+ pimlicoKey,
47
+ nearAdapter,
48
+ });
42
49
  }
43
50
  get safeNotDeployed() {
44
51
  return this._safeNotDeployed;
45
52
  }
46
- get nearEOA() {
53
+ get mpcAddress() {
47
54
  return this.nearAdapter.address;
48
55
  }
49
56
  async getSafeBalance() {
50
- return await this.provider.getBalance(this.safeAddress);
57
+ return await this.provider.getBalance(this.address);
51
58
  }
52
59
  async buildTransaction(args) {
53
60
  const { transactions, usePaymaster } = args;
@@ -58,7 +65,7 @@ export class TransactionManager {
58
65
  throw new Error("Empty transaction set!");
59
66
  }
60
67
  const tx = transactions.length > 1 ? encodeMulti(transactions) : transactions[0];
61
- const rawUserOp = await this.safePack.buildUserOp(tx, this.safeAddress, gasFees, this.setup, this.safeNotDeployed, this.safeSaltNonce);
68
+ const rawUserOp = await this.safePack.buildUserOp(tx, this.address, gasFees, this.setup, this.safeNotDeployed, this.safeSaltNonce);
62
69
  const paymasterData = await this.bundler.getPaymasterData(rawUserOp, usePaymaster, this.safeNotDeployed);
63
70
  const unsignedUserOp = { ...rawUserOp, ...paymasterData };
64
71
  return unsignedUserOp;
@@ -72,6 +79,9 @@ export class TransactionManager {
72
79
  }
73
80
  async encodeSignRequest(tx) {
74
81
  // TODO - This is sloppy and ignores ChainId!
82
+ if (tx.chainId !== this.chainId) {
83
+ throw new Error(`Transaciton request for invalid ChainId ${tx.chainId} != ${this.chainId}`);
84
+ }
75
85
  const unsignedUserOp = await this.buildTransaction({
76
86
  transactions: [
77
87
  {
@@ -100,12 +110,12 @@ export class TransactionManager {
100
110
  console.log("userOp Receipt", userOpReceipt);
101
111
  // Update safeNotDeployed after the first transaction
102
112
  this._safeNotDeployed =
103
- (await this.provider.getCode(this.safeAddress)) === "0x";
113
+ (await this.provider.getCode(this.address)) === "0x";
104
114
  return userOpReceipt;
105
115
  }
106
116
  addOwnerTx(address) {
107
117
  return {
108
- to: this.safeAddress,
118
+ to: this.address,
109
119
  value: "0",
110
120
  data: this.safePack.singleton.interface.encodeFunctionData("addOwnerWithThreshold", [address, 1]),
111
121
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "near-safe",
3
- "version": "0.0.5",
3
+ "version": "0.1.1",
4
4
  "license": "MIT",
5
5
  "description": "An SDK for controlling Ethereum Smart Accounts via ERC4337 from a Near Account.",
6
6
  "author": "bh2smith",