near-safe 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -27,15 +27,16 @@ yarn install
27
27
  Create a `.env` (or use our `.env.sample`) file in the root of the project and add the following environment variables:
28
28
 
29
29
  ```sh
30
- ETH_RPC=https://rpc2.sepolia.org
31
-
32
30
  NEAR_ACCOUNT_ID=
33
- NEAR_ACCOUNT_PRIVATE_KEY=
34
-
35
31
  # Head to https://www.pimlico.io/ for an API key
36
32
  PIMLICO_KEY=
37
33
  ```
38
34
 
35
+ To use the CLI tool provided here in `examples/*` you will also need to provide a privateKey for your Near account.
36
+
37
+ ```sh
38
+ NEAR_ACCOUNT_PRIVATE_KEY=
39
+ ```
39
40
 
40
41
  ## Usage
41
42
 
@@ -1,3 +1,4 @@
1
1
  export * from "./tx-manager";
2
2
  export * from "./types";
3
3
  export * from "./util";
4
+ export { Network, BaseTx, SignRequestData, populateTx } from "near-ca";
package/dist/cjs/index.js CHANGED
@@ -14,6 +14,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.populateTx = exports.Network = void 0;
17
18
  __exportStar(require("./tx-manager"), exports);
18
19
  __exportStar(require("./types"), exports);
19
20
  __exportStar(require("./util"), exports);
21
+ var near_ca_1 = require("near-ca");
22
+ Object.defineProperty(exports, "Network", { enumerable: true, get: function () { return near_ca_1.Network; } });
23
+ Object.defineProperty(exports, "populateTx", { enumerable: true, get: function () { return near_ca_1.populateTx; } });
@@ -3,7 +3,10 @@ import { GasPrices, PaymasterData, UnsignedUserOperation, UserOperation, UserOpe
3
3
  export declare class Erc4337Bundler {
4
4
  provider: ethers.JsonRpcProvider;
5
5
  entryPointAddress: string;
6
- constructor(bundlerUrl: string, entryPointAddress: string);
6
+ apiKey: string;
7
+ chainId: number;
8
+ constructor(entryPointAddress: string, apiKey: string, chainId: number);
9
+ client(chainId: number): ethers.JsonRpcProvider;
7
10
  getPaymasterData(rawUserOp: UnsignedUserOperation, usePaymaster: boolean, safeNotDeployed: boolean): Promise<PaymasterData>;
8
11
  sendUserOperation(userOp: UserOperation): Promise<string>;
9
12
  getGasPrice(): Promise<GasPrices>;
@@ -1,12 +1,22 @@
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
4
5
  const ethers_1 = require("ethers");
6
+ const viem_1 = require("viem");
5
7
  const util_1 = require("../util");
8
+ function bundlerUrl(chainId, apikey) {
9
+ return `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${apikey}`;
10
+ }
6
11
  class Erc4337Bundler {
7
- constructor(bundlerUrl, entryPointAddress) {
12
+ constructor(entryPointAddress, apiKey, chainId) {
8
13
  this.entryPointAddress = entryPointAddress;
9
- this.provider = new ethers_1.ethers.JsonRpcProvider(bundlerUrl);
14
+ this.apiKey = apiKey;
15
+ this.chainId = chainId;
16
+ this.provider = new ethers_1.ethers.JsonRpcProvider(bundlerUrl(chainId, apiKey));
17
+ }
18
+ client(chainId) {
19
+ return new ethers_1.ethers.JsonRpcProvider(bundlerUrl(chainId, this.apiKey));
10
20
  }
11
21
  async getPaymasterData(rawUserOp, usePaymaster, safeNotDeployed) {
12
22
  // TODO: Keep this option out of the bundler
@@ -53,8 +63,8 @@ exports.Erc4337Bundler = Erc4337Bundler;
53
63
  // TODO(bh2smith) Should probably get reasonable estimates here:
54
64
  const defaultPaymasterData = (safeNotDeployed) => {
55
65
  return {
56
- verificationGasLimit: ethers_1.ethers.toBeHex(safeNotDeployed ? 500000 : 100000),
57
- callGasLimit: ethers_1.ethers.toBeHex(100000),
58
- preVerificationGas: ethers_1.ethers.toBeHex(100000),
66
+ verificationGasLimit: (0, viem_1.toHex)(safeNotDeployed ? 500000 : 100000),
67
+ callGasLimit: (0, viem_1.toHex)(100000),
68
+ preVerificationGas: (0, viem_1.toHex)(100000),
59
69
  };
60
70
  };
@@ -0,0 +1,3 @@
1
+ import { MetaTransaction } from "../types";
2
+ export declare const MULTI_SEND_ABI: string[];
3
+ export declare function encodeMulti(transactions: readonly MetaTransaction[], multiSendContractAddress?: string): MetaTransaction;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MULTI_SEND_ABI = void 0;
4
+ exports.encodeMulti = encodeMulti;
5
+ const viem_1 = require("viem");
6
+ const types_1 = require("../types");
7
+ exports.MULTI_SEND_ABI = ["function multiSend(bytes memory transactions)"];
8
+ const MULTISEND_141 = "0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526";
9
+ const MULTISEND_CALLONLY_141 = "0x9641d764fc13c8B624c04430C7356C1C7C8102e2";
10
+ /// Encodes the transaction as packed bytes of:
11
+ /// - `operation` as a `uint8` with `0` for a `call` or `1` for a `delegatecall` (=> 1 byte),
12
+ /// - `to` as an `address` (=> 20 bytes),
13
+ /// - `value` as a `uint256` (=> 32 bytes),
14
+ /// - length of `data` as a `uint256` (=> 32 bytes),
15
+ /// - `data` as `bytes`.
16
+ const encodeMetaTx = (tx) => (0, viem_1.encodePacked)(["uint8", "address", "uint256", "uint256", "bytes"], [
17
+ tx.operation || types_1.OperationType.Call,
18
+ tx.to,
19
+ BigInt(tx.value),
20
+ BigInt((0, viem_1.size)(tx.data)),
21
+ tx.data,
22
+ ]);
23
+ const remove0x = (hexString) => hexString.slice(2);
24
+ // Encodes a batch of module transactions into a single multiSend module transaction.
25
+ // A module transaction is an object with fields corresponding to a Gnosis Safe's (i.e., Zodiac IAvatar's) `execTransactionFromModule` method parameters.
26
+ function encodeMulti(transactions, multiSendContractAddress = transactions.some((t) => t.operation === types_1.OperationType.DelegateCall)
27
+ ? MULTISEND_141
28
+ : MULTISEND_CALLONLY_141) {
29
+ const encodedTransactions = "0x" + transactions.map(encodeMetaTx).map(remove0x).join("");
30
+ return {
31
+ operation: types_1.OperationType.DelegateCall,
32
+ to: multiSendContractAddress,
33
+ value: "0x00",
34
+ data: (0, viem_1.encodeFunctionData)({
35
+ abi: (0, viem_1.parseAbi)(exports.MULTI_SEND_ABI),
36
+ functionName: "multiSend",
37
+ args: [encodedTransactions],
38
+ }),
39
+ };
40
+ }
@@ -1,6 +1,6 @@
1
1
  import { ethers } from "ethers";
2
- import { GasPrice, UnsignedUserOperation, UserOperation } from "../types";
3
- import { MetaTransaction } from "ethers-multisend";
2
+ import { Address, Hash, Hex } from "viem";
3
+ import { GasPrice, MetaTransaction, UnsignedUserOperation, UserOperation } from "../types";
4
4
  /**
5
5
  * All contracts used in account creation & execution
6
6
  */
@@ -12,13 +12,13 @@ export declare class ContractSuite {
12
12
  moduleSetup: ethers.Contract;
13
13
  entryPoint: ethers.Contract;
14
14
  constructor(provider: ethers.JsonRpcProvider, singleton: ethers.Contract, proxyFactory: ethers.Contract, m4337: ethers.Contract, moduleSetup: ethers.Contract, entryPoint: ethers.Contract);
15
- static init(provider: ethers.JsonRpcProvider): Promise<ContractSuite>;
16
- addressForSetup(setup: ethers.BytesLike, saltNonce?: string): Promise<string>;
17
- getSetup(owners: string[]): Promise<string>;
18
- getOpHash(unsignedUserOp: UserOperation): Promise<string>;
15
+ static init(): Promise<ContractSuite>;
16
+ addressForSetup(setup: ethers.BytesLike, saltNonce?: string): Promise<Address>;
17
+ getSetup(owners: string[]): Promise<Hex>;
18
+ getOpHash(unsignedUserOp: UserOperation): Promise<Hash>;
19
19
  factoryDataForSetup(safeNotDeployed: boolean, setup: string, safeSaltNonce: string): {
20
- factory?: ethers.AddressLike;
21
- factoryData?: string;
20
+ factory?: Address;
21
+ factoryData?: Hex;
22
22
  };
23
- buildUserOp(txData: MetaTransaction, safeAddress: ethers.AddressLike, feeData: GasPrice, setup: string, safeNotDeployed: boolean, safeSaltNonce: string): Promise<UnsignedUserOperation>;
23
+ buildUserOp(txData: MetaTransaction, safeAddress: Address, feeData: GasPrice, setup: string, safeNotDeployed: boolean, safeSaltNonce: string): Promise<UnsignedUserOperation>;
24
24
  }
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ContractSuite = void 0;
4
- const ethers_1 = require("ethers");
5
4
  const safe_deployments_1 = require("@safe-global/safe-deployments");
6
5
  const safe_modules_deployments_1 = require("@safe-global/safe-modules-deployments");
6
+ const ethers_1 = require("ethers");
7
7
  const util_1 = require("../util");
8
8
  /**
9
9
  * All contracts used in account creation & execution
@@ -17,16 +17,12 @@ class ContractSuite {
17
17
  this.moduleSetup = moduleSetup;
18
18
  this.entryPoint = entryPoint;
19
19
  }
20
- static async init(provider) {
20
+ static async init() {
21
+ // TODO - this is a cheeky hack.
22
+ const provider = new ethers_1.ethers.JsonRpcProvider("https://rpc2.sepolia.org");
21
23
  const safeDeployment = (fn) => getDeployment(fn, { provider, version: "1.4.1" });
22
24
  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
- }
25
+ return getDeployment(fn, { provider, version: "0.3.0" });
30
26
  };
31
27
  // Need this first to get entryPoint address
32
28
  const m4337 = await m4337Deployment(safe_modules_deployments_1.getSafe4337ModuleDeployment);
@@ -73,16 +69,15 @@ class ContractSuite {
73
69
  ]);
74
70
  return setup;
75
71
  }
76
- async getOpHash(unsignedUserOp
77
- // paymasterData: PaymasterData
78
- ) {
72
+ async getOpHash(unsignedUserOp) {
73
+ const { factory, factoryData, verificationGasLimit, callGasLimit, maxPriorityFeePerGas, maxFeePerGas, } = unsignedUserOp;
79
74
  return this.m4337.getOperationHash({
80
75
  ...unsignedUserOp,
81
- initCode: unsignedUserOp.factory
82
- ? ethers_1.ethers.solidityPacked(["address", "bytes"], [unsignedUserOp.factory, unsignedUserOp.factoryData])
76
+ initCode: factory
77
+ ? ethers_1.ethers.solidityPacked(["address", "bytes"], [factory, factoryData])
83
78
  : "0x",
84
- accountGasLimits: (0, util_1.packGas)(unsignedUserOp.verificationGasLimit, unsignedUserOp.callGasLimit),
85
- gasFees: (0, util_1.packGas)(unsignedUserOp.maxPriorityFeePerGas, unsignedUserOp.maxFeePerGas),
79
+ accountGasLimits: (0, util_1.packGas)(verificationGasLimit, callGasLimit),
80
+ gasFees: (0, util_1.packGas)(maxPriorityFeePerGas, maxFeePerGas),
86
81
  paymasterAndData: (0, util_1.packPaymasterData)(unsignedUserOp),
87
82
  signature: util_1.PLACEHOLDER_SIG,
88
83
  });
@@ -116,8 +111,17 @@ exports.ContractSuite = ContractSuite;
116
111
  async function getDeployment(fn, { provider, version }) {
117
112
  const { chainId } = await provider.getNetwork();
118
113
  const deployment = fn({ version });
119
- if (!deployment || !deployment.networkAddresses[`${chainId}`]) {
114
+ if (!deployment) {
120
115
  throw new Error(`Deployment not found for ${fn.name} version ${version} on chainId ${chainId}`);
121
116
  }
122
- return new ethers_1.ethers.Contract(deployment.networkAddresses[`${chainId}`], deployment.abi, provider);
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"];
125
+ }
126
+ return new ethers_1.ethers.Contract(address, deployment.abi, provider);
123
127
  }
@@ -1,42 +1,43 @@
1
- import { ethers } from "ethers";
1
+ import { FinalExecutionOutcome } from "near-api-js/lib/providers";
2
2
  import { NearEthAdapter, NearEthTxData, BaseTx } from "near-ca";
3
+ import { Address, Hash, Hex } from "viem";
3
4
  import { Erc4337Bundler } from "./lib/bundler";
4
- import { UserOperation, UserOperationReceipt } from "./types";
5
- import { MetaTransaction } from "ethers-multisend";
6
5
  import { ContractSuite } from "./lib/safe";
6
+ import { MetaTransaction, UserOperation, UserOperationReceipt } from "./types";
7
7
  export declare class TransactionManager {
8
- readonly provider: ethers.JsonRpcProvider;
9
8
  readonly nearAdapter: NearEthAdapter;
9
+ readonly address: Address;
10
+ readonly entryPointAddress: Address;
10
11
  private safePack;
11
- private bundler;
12
12
  private setup;
13
- readonly address: string;
14
- readonly chainId: number;
13
+ private pimlicoKey;
15
14
  private safeSaltNonce;
16
- private _safeNotDeployed;
17
- constructor(provider: ethers.JsonRpcProvider, nearAdapter: NearEthAdapter, safePack: ContractSuite, bundler: Erc4337Bundler, setup: string, chainId: number, safeAddress: string, safeSaltNonce: string, safeNotDeployed: boolean);
15
+ private deployedChains;
16
+ constructor(nearAdapter: NearEthAdapter, safePack: ContractSuite, pimlicoKey: string, setup: string, safeAddress: Address, entryPointAddress: Address, safeSaltNonce: string);
18
17
  static create(config: {
19
- ethRpc: string;
18
+ accountId: string;
19
+ mpcContractId: string;
20
20
  pimlicoKey: string;
21
- nearAdapter: NearEthAdapter;
21
+ privateKey?: string;
22
22
  safeSaltNonce?: string;
23
23
  }): Promise<TransactionManager>;
24
- static fromChainId(args: {
25
- chainId: number;
26
- nearAdapter: NearEthAdapter;
27
- pimlicoKey: string;
28
- }): Promise<TransactionManager>;
29
- get safeNotDeployed(): boolean;
30
- get mpcAddress(): `0x${string}`;
31
- getSafeBalance(): Promise<bigint>;
24
+ get mpcAddress(): Address;
25
+ getBalance(chainId: number): Promise<bigint>;
26
+ bundlerForChainId(chainId: number): Erc4337Bundler;
32
27
  buildTransaction(args: {
28
+ chainId: number;
33
29
  transactions: MetaTransaction[];
34
30
  usePaymaster: boolean;
35
31
  }): Promise<UserOperation>;
36
- signTransaction(safeOpHash: string): Promise<string>;
37
- opHash(userOp: UserOperation): Promise<string>;
32
+ signTransaction(safeOpHash: Hex): Promise<Hex>;
33
+ opHash(userOp: UserOperation): Promise<Hash>;
38
34
  encodeSignRequest(tx: BaseTx): Promise<NearEthTxData>;
39
- executeTransaction(userOp: UserOperation): Promise<UserOperationReceipt>;
35
+ executeTransaction(chainId: number, userOp: UserOperation): Promise<UserOperationReceipt>;
36
+ safeDeployed(chainId: number): Promise<boolean>;
40
37
  addOwnerTx(address: string): MetaTransaction;
41
- safeSufficientlyFunded(transactions: MetaTransaction[], gasCost: bigint): Promise<boolean>;
38
+ safeSufficientlyFunded(chainId: number, transactions: MetaTransaction[], gasCost: bigint): Promise<boolean>;
39
+ broadcastEvm(chainId: number, outcome: FinalExecutionOutcome, unsignedUserOp: UserOperation): Promise<{
40
+ signature: Hex;
41
+ receipt: UserOperationReceipt;
42
+ }>;
42
43
  }
@@ -1,82 +1,71 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TransactionManager = void 0;
4
- const ethers_1 = require("ethers");
5
4
  const near_ca_1 = require("near-ca");
5
+ const viem_1 = require("viem");
6
6
  const bundler_1 = require("./lib/bundler");
7
- const util_1 = require("./util");
8
- const near_1 = require("./lib/near");
9
- const ethers_multisend_1 = require("ethers-multisend");
7
+ const multisend_1 = require("./lib/multisend");
10
8
  const safe_1 = require("./lib/safe");
9
+ const util_1 = require("./util");
11
10
  class TransactionManager {
12
- constructor(provider, nearAdapter, safePack, bundler, setup, chainId, safeAddress, safeSaltNonce, safeNotDeployed) {
13
- this.provider = provider;
11
+ constructor(nearAdapter, safePack, pimlicoKey, setup, safeAddress, entryPointAddress, safeSaltNonce) {
14
12
  this.nearAdapter = nearAdapter;
15
13
  this.safePack = safePack;
16
- this.bundler = bundler;
14
+ this.pimlicoKey = pimlicoKey;
15
+ this.entryPointAddress = entryPointAddress;
17
16
  this.setup = setup;
18
- this.chainId = chainId;
19
17
  this.address = safeAddress;
20
18
  this.safeSaltNonce = safeSaltNonce;
21
- this._safeNotDeployed = safeNotDeployed;
19
+ this.deployedChains = new Set();
22
20
  }
23
21
  static async create(config) {
24
- const { nearAdapter, pimlicoKey } = config;
25
- const provider = new ethers_1.ethers.JsonRpcProvider(config.ethRpc);
26
- const chainId = (await provider.getNetwork()).chainId;
27
- const safePack = await safe_1.ContractSuite.init(provider);
22
+ const { pimlicoKey } = config;
23
+ const [nearAdapter, safePack] = await Promise.all([
24
+ (0, near_ca_1.setupAdapter)({ ...config }),
25
+ safe_1.ContractSuite.init(),
26
+ ]);
28
27
  console.log(`Near Adapter: ${nearAdapter.nearAccountId()} <> ${nearAdapter.address}`);
29
- const bundler = new bundler_1.Erc4337Bundler(`https://api.pimlico.io/v2/${chainId}/rpc?apikey=${pimlicoKey}`, await safePack.entryPoint.getAddress());
30
28
  const setup = await safePack.getSetup([nearAdapter.address]);
31
29
  const safeAddress = await safePack.addressForSetup(setup, config.safeSaltNonce);
32
- const safeNotDeployed = (await provider.getCode(safeAddress)) === "0x";
33
- console.log(`Safe Address: ${safeAddress} - deployed? ${!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
- });
43
- }
44
- get safeNotDeployed() {
45
- return this._safeNotDeployed;
30
+ const entryPointAddress = (await safePack.entryPoint.getAddress());
31
+ console.log(`Safe Address: ${safeAddress}`);
32
+ return new TransactionManager(nearAdapter, safePack, pimlicoKey, setup, safeAddress, entryPointAddress, config.safeSaltNonce || "0");
46
33
  }
47
34
  get mpcAddress() {
48
35
  return this.nearAdapter.address;
49
36
  }
50
- async getSafeBalance() {
51
- return await this.provider.getBalance(this.address);
37
+ async getBalance(chainId) {
38
+ const provider = near_ca_1.Network.fromChainId(chainId).client;
39
+ return await provider.getBalance({ address: this.address });
40
+ }
41
+ bundlerForChainId(chainId) {
42
+ return new bundler_1.Erc4337Bundler(this.entryPointAddress, this.pimlicoKey, chainId);
52
43
  }
53
44
  async buildTransaction(args) {
54
- const { transactions, usePaymaster } = args;
55
- const gasFees = (await this.bundler.getGasPrice()).fast;
56
- // const gasFees = await this.provider.getFeeData();
45
+ const { transactions, usePaymaster, chainId } = args;
46
+ const bundler = this.bundlerForChainId(chainId);
47
+ const gasFees = (await bundler.getGasPrice()).fast;
57
48
  // Build Singular MetaTransaction for Multisend from transaction list.
58
49
  if (transactions.length === 0) {
59
50
  throw new Error("Empty transaction set!");
60
51
  }
61
- const tx = transactions.length > 1 ? (0, ethers_multisend_1.encodeMulti)(transactions) : transactions[0];
62
- const rawUserOp = await this.safePack.buildUserOp(tx, this.address, gasFees, this.setup, this.safeNotDeployed, this.safeSaltNonce);
63
- const paymasterData = await this.bundler.getPaymasterData(rawUserOp, usePaymaster, this.safeNotDeployed);
52
+ const tx = transactions.length > 1 ? (0, multisend_1.encodeMulti)(transactions) : transactions[0];
53
+ const safeNotDeployed = !(await this.safeDeployed(chainId));
54
+ const rawUserOp = await this.safePack.buildUserOp(tx, this.address, gasFees, this.setup, safeNotDeployed, this.safeSaltNonce);
55
+ const paymasterData = await bundler.getPaymasterData(rawUserOp, usePaymaster, safeNotDeployed);
64
56
  const unsignedUserOp = { ...rawUserOp, ...paymasterData };
65
57
  return unsignedUserOp;
66
58
  }
67
59
  async signTransaction(safeOpHash) {
68
- const signature = await (0, near_1.getNearSignature)(this.nearAdapter, safeOpHash);
60
+ const signature = await this.nearAdapter.sign(safeOpHash);
69
61
  return (0, util_1.packSignature)(signature);
70
62
  }
71
63
  async opHash(userOp) {
72
64
  return this.safePack.getOpHash(userOp);
73
65
  }
74
66
  async encodeSignRequest(tx) {
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
- }
79
67
  const unsignedUserOp = await this.buildTransaction({
68
+ chainId: tx.chainId,
80
69
  transactions: [
81
70
  {
82
71
  to: tx.to,
@@ -97,16 +86,27 @@ class TransactionManager {
97
86
  evmMessage: JSON.stringify(unsignedUserOp),
98
87
  };
99
88
  }
100
- async executeTransaction(userOp) {
101
- const userOpHash = await this.bundler.sendUserOperation(userOp);
89
+ async executeTransaction(chainId, userOp) {
90
+ const bundler = this.bundlerForChainId(chainId);
91
+ const userOpHash = await bundler.sendUserOperation(userOp);
102
92
  console.log("UserOp Hash", userOpHash);
103
- const userOpReceipt = await this.bundler.getUserOpReceipt(userOpHash);
93
+ const userOpReceipt = await bundler.getUserOpReceipt(userOpHash);
104
94
  console.log("userOp Receipt", userOpReceipt);
105
95
  // Update safeNotDeployed after the first transaction
106
- this._safeNotDeployed =
107
- (await this.provider.getCode(this.address)) === "0x";
96
+ this.safeDeployed(chainId);
108
97
  return userOpReceipt;
109
98
  }
99
+ async safeDeployed(chainId) {
100
+ if (chainId in this.deployedChains) {
101
+ return true;
102
+ }
103
+ const provider = near_ca_1.Network.fromChainId(chainId).client;
104
+ const deployed = (await provider.getCode({ address: this.address })) !== "0x";
105
+ if (deployed) {
106
+ this.deployedChains.add(chainId);
107
+ }
108
+ return deployed;
109
+ }
110
110
  addOwnerTx(address) {
111
111
  return {
112
112
  to: this.address,
@@ -114,13 +114,28 @@ class TransactionManager {
114
114
  data: this.safePack.singleton.interface.encodeFunctionData("addOwnerWithThreshold", [address, 1]),
115
115
  };
116
116
  }
117
- async safeSufficientlyFunded(transactions, gasCost) {
117
+ async safeSufficientlyFunded(chainId, transactions, gasCost) {
118
118
  const txValue = transactions.reduce((acc, tx) => acc + BigInt(tx.value), 0n);
119
119
  if (txValue + gasCost === 0n) {
120
120
  return true;
121
121
  }
122
- const safeBalance = await this.getSafeBalance();
122
+ const safeBalance = await this.getBalance(chainId);
123
123
  return txValue + gasCost < safeBalance;
124
124
  }
125
+ async broadcastEvm(chainId, outcome, unsignedUserOp) {
126
+ const signature = (0, util_1.packSignature)((0, viem_1.serializeSignature)((0, near_ca_1.signatureFromOutcome)(outcome)));
127
+ try {
128
+ return {
129
+ signature,
130
+ receipt: await this.executeTransaction(chainId, {
131
+ ...unsignedUserOp,
132
+ signature,
133
+ }),
134
+ };
135
+ }
136
+ catch (error) {
137
+ throw new Error(`Failed EVM broadcast: ${error instanceof Error ? error.message : String(error)}`);
138
+ }
139
+ }
125
140
  }
126
141
  exports.TransactionManager = TransactionManager;
@@ -1,30 +1,30 @@
1
- import { ethers } from "ethers";
1
+ import { Address, Hex } from "viem";
2
2
  export interface UnsignedUserOperation {
3
- sender: ethers.AddressLike;
3
+ sender: Address;
4
4
  nonce: string;
5
- factory?: ethers.AddressLike;
6
- factoryData?: ethers.BytesLike;
7
- callData: string;
8
- maxPriorityFeePerGas: string;
9
- maxFeePerGas: string;
5
+ factory?: Address;
6
+ factoryData?: Hex;
7
+ callData: Hex;
8
+ maxPriorityFeePerGas: Hex;
9
+ maxFeePerGas: Hex;
10
10
  }
11
11
  /**
12
12
  * Supported Representation of UserOperation for EntryPoint v0.7
13
13
  */
14
14
  export interface UserOperation extends UnsignedUserOperation {
15
- verificationGasLimit: string;
16
- callGasLimit: string;
17
- preVerificationGas: string;
18
- signature?: string;
15
+ verificationGasLimit: Hex;
16
+ callGasLimit: Hex;
17
+ preVerificationGas: Hex;
18
+ signature?: Hex;
19
19
  }
20
20
  export interface PaymasterData {
21
- paymaster?: string;
22
- paymasterData?: string;
23
- paymasterVerificationGasLimit?: string;
24
- paymasterPostOpGasLimit?: string;
25
- verificationGasLimit: string;
26
- callGasLimit: string;
27
- preVerificationGas: string;
21
+ paymaster?: Address;
22
+ paymasterData?: Hex;
23
+ paymasterVerificationGasLimit?: Hex;
24
+ paymasterPostOpGasLimit?: Hex;
25
+ verificationGasLimit: Hex;
26
+ callGasLimit: Hex;
27
+ preVerificationGas: Hex;
28
28
  }
29
29
  export interface UserOptions {
30
30
  usePaymaster: boolean;
@@ -32,10 +32,7 @@ export interface UserOptions {
32
32
  mpcContractId: string;
33
33
  recoveryAddress?: string;
34
34
  }
35
- export type TStatus = "success" | "reverted";
36
- export type Address = ethers.AddressLike;
37
- export type Hex = `0x${string}`;
38
- export type Hash = `0x${string}`;
35
+ export type TxStatus = "success" | "reverted";
39
36
  interface Log {
40
37
  logIndex: string;
41
38
  transactionIndex: string;
@@ -49,19 +46,19 @@ interface Log {
49
46
  interface Receipt {
50
47
  transactionHash: Hex;
51
48
  transactionIndex: bigint;
52
- blockHash: Hash;
49
+ blockHash: Hex;
53
50
  blockNumber: bigint;
54
51
  from: Address;
55
- to: Address | null;
52
+ to?: Address;
56
53
  cumulativeGasUsed: bigint;
57
- status: TStatus;
54
+ status: TxStatus;
58
55
  gasUsed: bigint;
59
- contractAddress: Address | null;
56
+ contractAddress?: Address;
60
57
  logsBloom: Hex;
61
58
  effectiveGasPrice: bigint;
62
59
  }
63
60
  export type UserOperationReceipt = {
64
- userOpHash: Hash;
61
+ userOpHash: Hex;
65
62
  entryPoint: Address;
66
63
  sender: Address;
67
64
  nonce: bigint;
@@ -82,4 +79,14 @@ export interface GasPrice {
82
79
  maxFeePerGas: Hex;
83
80
  maxPriorityFeePerGas: Hex;
84
81
  }
82
+ export declare enum OperationType {
83
+ Call = 0,
84
+ DelegateCall = 1
85
+ }
86
+ export interface MetaTransaction {
87
+ readonly to: string;
88
+ readonly value: string;
89
+ readonly data: string;
90
+ readonly operation?: OperationType;
91
+ }
85
92
  export {};
package/dist/cjs/types.js CHANGED
@@ -1,2 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OperationType = void 0;
4
+ var OperationType;
5
+ (function (OperationType) {
6
+ OperationType[OperationType["Call"] = 0] = "Call";
7
+ OperationType[OperationType["DelegateCall"] = 1] = "DelegateCall";
8
+ })(OperationType || (exports.OperationType = OperationType = {}));
@@ -1,8 +1,9 @@
1
- import { ethers } from "ethers";
2
- import { PaymasterData } from "./types";
3
- import { MetaTransaction } from "ethers-multisend";
4
- export declare const PLACEHOLDER_SIG: string;
5
- export declare const packGas: (hi: ethers.BigNumberish, lo: ethers.BigNumberish) => string;
6
- export declare function packSignature(signature: string, validFrom?: number, validTo?: number): string;
7
- export declare function packPaymasterData(data: PaymasterData): string;
1
+ import { Hex } from "viem";
2
+ import { PaymasterData, MetaTransaction } from "./types";
3
+ export declare const PLACEHOLDER_SIG: `0x${string}`;
4
+ type IntLike = Hex | bigint | string | number;
5
+ export declare const packGas: (hi: IntLike, lo: IntLike) => string;
6
+ export declare function packSignature(signature: `0x${string}`, validFrom?: number, validTo?: number): Hex;
7
+ export declare function packPaymasterData(data: PaymasterData): Hex;
8
8
  export declare function containsValue(transactions: MetaTransaction[]): boolean;
9
+ export {};
package/dist/cjs/util.js CHANGED
@@ -4,22 +4,22 @@ exports.packGas = exports.PLACEHOLDER_SIG = void 0;
4
4
  exports.packSignature = packSignature;
5
5
  exports.packPaymasterData = packPaymasterData;
6
6
  exports.containsValue = containsValue;
7
- const ethers_1 = require("ethers");
8
- exports.PLACEHOLDER_SIG = ethers_1.ethers.solidityPacked(["uint48", "uint48"], [0, 0]);
9
- const packGas = (hi, lo) => ethers_1.ethers.solidityPacked(["uint128", "uint128"], [hi, lo]);
7
+ const viem_1 = require("viem");
8
+ exports.PLACEHOLDER_SIG = (0, viem_1.encodePacked)(["uint48", "uint48"], [0, 0]);
9
+ const packGas = (hi, lo) => (0, viem_1.encodePacked)(["uint128", "uint128"], [BigInt(hi), BigInt(lo)]);
10
10
  exports.packGas = packGas;
11
11
  function packSignature(signature, validFrom = 0, validTo = 0) {
12
- return ethers_1.ethers.solidityPacked(["uint48", "uint48", "bytes"], [validFrom, validTo, signature]);
12
+ return (0, viem_1.encodePacked)(["uint48", "uint48", "bytes"], [validFrom, validTo, signature]);
13
13
  }
14
14
  function packPaymasterData(data) {
15
- return data.paymaster
16
- ? ethers_1.ethers.hexlify(ethers_1.ethers.concat([
15
+ return (data.paymaster
16
+ ? (0, viem_1.concatHex)([
17
17
  data.paymaster,
18
- ethers_1.ethers.toBeHex(data.paymasterVerificationGasLimit || "0x", 16),
19
- ethers_1.ethers.toBeHex(data.paymasterPostOpGasLimit || "0x", 16),
18
+ (0, viem_1.toHex)(BigInt(data.paymasterVerificationGasLimit || 0n), { size: 16 }),
19
+ (0, viem_1.toHex)(BigInt(data.paymasterPostOpGasLimit || 0n), { size: 16 }),
20
20
  data.paymasterData || "0x",
21
- ]))
22
- : "0x";
21
+ ])
22
+ : "0x");
23
23
  }
24
24
  function containsValue(transactions) {
25
25
  return transactions.some((tx) => tx.value !== "0");