near-safe 0.1.1 → 0.2.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
@@ -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");