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.
@@ -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/esm/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./tx-manager";
2
2
  export * from "./types";
3
3
  export * from "./util";
4
+ export { Network, populateTx } from "near-ca";
@@ -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,11 +1,23 @@
1
+ // TODO: Ethers dependency is only for Generic HTTP Provider
1
2
  import { ethers } from "ethers";
3
+ import { toHex } from "viem";
2
4
  import { PLACEHOLDER_SIG } from "../util";
5
+ function bundlerUrl(chainId, apikey) {
6
+ return `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${apikey}`;
7
+ }
3
8
  export class Erc4337Bundler {
4
9
  provider;
5
10
  entryPointAddress;
6
- constructor(bundlerUrl, entryPointAddress) {
11
+ apiKey;
12
+ chainId;
13
+ constructor(entryPointAddress, apiKey, chainId) {
7
14
  this.entryPointAddress = entryPointAddress;
8
- this.provider = new ethers.JsonRpcProvider(bundlerUrl);
15
+ this.apiKey = apiKey;
16
+ this.chainId = chainId;
17
+ this.provider = new ethers.JsonRpcProvider(bundlerUrl(chainId, apiKey));
18
+ }
19
+ client(chainId) {
20
+ return new ethers.JsonRpcProvider(bundlerUrl(chainId, this.apiKey));
9
21
  }
10
22
  async getPaymasterData(rawUserOp, usePaymaster, safeNotDeployed) {
11
23
  // TODO: Keep this option out of the bundler
@@ -51,8 +63,8 @@ export class Erc4337Bundler {
51
63
  // TODO(bh2smith) Should probably get reasonable estimates here:
52
64
  const defaultPaymasterData = (safeNotDeployed) => {
53
65
  return {
54
- verificationGasLimit: ethers.toBeHex(safeNotDeployed ? 500000 : 100000),
55
- callGasLimit: ethers.toBeHex(100000),
56
- preVerificationGas: ethers.toBeHex(100000),
66
+ verificationGasLimit: toHex(safeNotDeployed ? 500000 : 100000),
67
+ callGasLimit: toHex(100000),
68
+ preVerificationGas: toHex(100000),
57
69
  };
58
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,36 @@
1
+ import { encodeFunctionData, encodePacked, parseAbi, size, } from "viem";
2
+ import { OperationType } from "../types";
3
+ export const MULTI_SEND_ABI = ["function multiSend(bytes memory transactions)"];
4
+ const MULTISEND_141 = "0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526";
5
+ const MULTISEND_CALLONLY_141 = "0x9641d764fc13c8B624c04430C7356C1C7C8102e2";
6
+ /// Encodes the transaction as packed bytes of:
7
+ /// - `operation` as a `uint8` with `0` for a `call` or `1` for a `delegatecall` (=> 1 byte),
8
+ /// - `to` as an `address` (=> 20 bytes),
9
+ /// - `value` as a `uint256` (=> 32 bytes),
10
+ /// - length of `data` as a `uint256` (=> 32 bytes),
11
+ /// - `data` as `bytes`.
12
+ const encodeMetaTx = (tx) => encodePacked(["uint8", "address", "uint256", "uint256", "bytes"], [
13
+ tx.operation || OperationType.Call,
14
+ tx.to,
15
+ BigInt(tx.value),
16
+ BigInt(size(tx.data)),
17
+ tx.data,
18
+ ]);
19
+ const remove0x = (hexString) => hexString.slice(2);
20
+ // Encodes a batch of module transactions into a single multiSend module transaction.
21
+ // A module transaction is an object with fields corresponding to a Gnosis Safe's (i.e., Zodiac IAvatar's) `execTransactionFromModule` method parameters.
22
+ export function encodeMulti(transactions, multiSendContractAddress = transactions.some((t) => t.operation === OperationType.DelegateCall)
23
+ ? MULTISEND_141
24
+ : MULTISEND_CALLONLY_141) {
25
+ const encodedTransactions = "0x" + transactions.map(encodeMetaTx).map(remove0x).join("");
26
+ return {
27
+ operation: OperationType.DelegateCall,
28
+ to: multiSendContractAddress,
29
+ value: "0x00",
30
+ data: encodeFunctionData({
31
+ abi: parseAbi(MULTI_SEND_ABI),
32
+ functionName: "multiSend",
33
+ args: [encodedTransactions],
34
+ }),
35
+ };
36
+ }
@@ -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,6 +1,6 @@
1
- import { ethers } from "ethers";
2
1
  import { getProxyFactoryDeployment, getSafeL2SingletonDeployment, } from "@safe-global/safe-deployments";
3
2
  import { getSafe4337ModuleDeployment, getSafeModuleSetupDeployment, } from "@safe-global/safe-modules-deployments";
3
+ import { ethers } from "ethers";
4
4
  import { PLACEHOLDER_SIG, packGas, packPaymasterData } from "../util";
5
5
  /**
6
6
  * All contracts used in account creation & execution
@@ -20,16 +20,12 @@ export class ContractSuite {
20
20
  this.moduleSetup = moduleSetup;
21
21
  this.entryPoint = entryPoint;
22
22
  }
23
- static async init(provider) {
23
+ static async init() {
24
+ // TODO - this is a cheeky hack.
25
+ const provider = new ethers.JsonRpcProvider("https://rpc2.sepolia.org");
24
26
  const safeDeployment = (fn) => getDeployment(fn, { provider, version: "1.4.1" });
25
27
  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
- }
28
+ return getDeployment(fn, { provider, version: "0.3.0" });
33
29
  };
34
30
  // Need this first to get entryPoint address
35
31
  const m4337 = await m4337Deployment(getSafe4337ModuleDeployment);
@@ -76,16 +72,15 @@ export class ContractSuite {
76
72
  ]);
77
73
  return setup;
78
74
  }
79
- async getOpHash(unsignedUserOp
80
- // paymasterData: PaymasterData
81
- ) {
75
+ async getOpHash(unsignedUserOp) {
76
+ const { factory, factoryData, verificationGasLimit, callGasLimit, maxPriorityFeePerGas, maxFeePerGas, } = unsignedUserOp;
82
77
  return this.m4337.getOperationHash({
83
78
  ...unsignedUserOp,
84
- initCode: unsignedUserOp.factory
85
- ? ethers.solidityPacked(["address", "bytes"], [unsignedUserOp.factory, unsignedUserOp.factoryData])
79
+ initCode: factory
80
+ ? ethers.solidityPacked(["address", "bytes"], [factory, factoryData])
86
81
  : "0x",
87
- accountGasLimits: packGas(unsignedUserOp.verificationGasLimit, unsignedUserOp.callGasLimit),
88
- gasFees: packGas(unsignedUserOp.maxPriorityFeePerGas, unsignedUserOp.maxFeePerGas),
82
+ accountGasLimits: packGas(verificationGasLimit, callGasLimit),
83
+ gasFees: packGas(maxPriorityFeePerGas, maxFeePerGas),
89
84
  paymasterAndData: packPaymasterData(unsignedUserOp),
90
85
  signature: PLACEHOLDER_SIG,
91
86
  });
@@ -118,8 +113,17 @@ export class ContractSuite {
118
113
  async function getDeployment(fn, { provider, version }) {
119
114
  const { chainId } = await provider.getNetwork();
120
115
  const deployment = fn({ version });
121
- if (!deployment || !deployment.networkAddresses[`${chainId}`]) {
116
+ if (!deployment) {
122
117
  throw new Error(`Deployment not found for ${fn.name} version ${version} on chainId ${chainId}`);
123
118
  }
124
- return new ethers.Contract(deployment.networkAddresses[`${chainId}`], deployment.abi, provider);
119
+ let address = deployment.networkAddresses[`${chainId}`];
120
+ if (!address) {
121
+ // console.warn(
122
+ // `Deployment asset ${fn.name} not listed on chainId ${chainId}, using likely fallback. For more info visit https://github.com/safe-global/safe-modules-deployments`
123
+ // );
124
+ // TODO: This is a cheeky hack. Real solution proposed in
125
+ // https://github.com/Mintbase/near-safe/issues/42
126
+ address = deployment.networkAddresses["11155111"];
127
+ }
128
+ return new ethers.Contract(address, deployment.abi, provider);
125
129
  }
@@ -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,88 +1,76 @@
1
- import { ethers } from "ethers";
2
- import { Network } from "near-ca";
1
+ import { Network, setupAdapter, signatureFromOutcome, } from "near-ca";
2
+ import { serializeSignature } from "viem";
3
3
  import { Erc4337Bundler } from "./lib/bundler";
4
- import { packSignature } from "./util";
5
- import { getNearSignature } from "./lib/near";
6
- import { encodeMulti } from "ethers-multisend";
4
+ import { encodeMulti } from "./lib/multisend";
7
5
  import { ContractSuite } from "./lib/safe";
6
+ import { packSignature } from "./util";
8
7
  export class TransactionManager {
9
- provider;
10
8
  nearAdapter;
9
+ address;
10
+ entryPointAddress;
11
11
  safePack;
12
- bundler;
13
12
  setup;
14
- address;
15
- chainId;
13
+ pimlicoKey;
16
14
  safeSaltNonce;
17
- _safeNotDeployed;
18
- constructor(provider, nearAdapter, safePack, bundler, setup, chainId, safeAddress, safeSaltNonce, safeNotDeployed) {
19
- this.provider = provider;
15
+ deployedChains;
16
+ constructor(nearAdapter, safePack, pimlicoKey, setup, safeAddress, entryPointAddress, safeSaltNonce) {
20
17
  this.nearAdapter = nearAdapter;
21
18
  this.safePack = safePack;
22
- this.bundler = bundler;
19
+ this.pimlicoKey = pimlicoKey;
20
+ this.entryPointAddress = entryPointAddress;
23
21
  this.setup = setup;
24
- this.chainId = chainId;
25
22
  this.address = safeAddress;
26
23
  this.safeSaltNonce = safeSaltNonce;
27
- this._safeNotDeployed = safeNotDeployed;
24
+ this.deployedChains = new Set();
28
25
  }
29
26
  static async create(config) {
30
- const { nearAdapter, pimlicoKey } = config;
31
- const provider = new ethers.JsonRpcProvider(config.ethRpc);
32
- const chainId = (await provider.getNetwork()).chainId;
33
- const safePack = await ContractSuite.init(provider);
27
+ const { pimlicoKey } = config;
28
+ const [nearAdapter, safePack] = await Promise.all([
29
+ setupAdapter({ ...config }),
30
+ ContractSuite.init(),
31
+ ]);
34
32
  console.log(`Near Adapter: ${nearAdapter.nearAccountId()} <> ${nearAdapter.address}`);
35
- const bundler = new Erc4337Bundler(`https://api.pimlico.io/v2/${chainId}/rpc?apikey=${pimlicoKey}`, await safePack.entryPoint.getAddress());
36
33
  const setup = await safePack.getSetup([nearAdapter.address]);
37
34
  const safeAddress = await safePack.addressForSetup(setup, config.safeSaltNonce);
38
- const safeNotDeployed = (await provider.getCode(safeAddress)) === "0x";
39
- console.log(`Safe Address: ${safeAddress} - deployed? ${!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
- });
49
- }
50
- get safeNotDeployed() {
51
- return this._safeNotDeployed;
35
+ const entryPointAddress = (await safePack.entryPoint.getAddress());
36
+ console.log(`Safe Address: ${safeAddress}`);
37
+ return new TransactionManager(nearAdapter, safePack, pimlicoKey, setup, safeAddress, entryPointAddress, config.safeSaltNonce || "0");
52
38
  }
53
39
  get mpcAddress() {
54
40
  return this.nearAdapter.address;
55
41
  }
56
- async getSafeBalance() {
57
- return await this.provider.getBalance(this.address);
42
+ async getBalance(chainId) {
43
+ const provider = Network.fromChainId(chainId).client;
44
+ return await provider.getBalance({ address: this.address });
45
+ }
46
+ bundlerForChainId(chainId) {
47
+ return new Erc4337Bundler(this.entryPointAddress, this.pimlicoKey, chainId);
58
48
  }
59
49
  async buildTransaction(args) {
60
- const { transactions, usePaymaster } = args;
61
- const gasFees = (await this.bundler.getGasPrice()).fast;
62
- // const gasFees = await this.provider.getFeeData();
50
+ const { transactions, usePaymaster, chainId } = args;
51
+ const bundler = this.bundlerForChainId(chainId);
52
+ const gasFees = (await bundler.getGasPrice()).fast;
63
53
  // Build Singular MetaTransaction for Multisend from transaction list.
64
54
  if (transactions.length === 0) {
65
55
  throw new Error("Empty transaction set!");
66
56
  }
67
57
  const tx = transactions.length > 1 ? encodeMulti(transactions) : transactions[0];
68
- const rawUserOp = await this.safePack.buildUserOp(tx, this.address, gasFees, this.setup, this.safeNotDeployed, this.safeSaltNonce);
69
- const paymasterData = await this.bundler.getPaymasterData(rawUserOp, usePaymaster, this.safeNotDeployed);
58
+ const safeNotDeployed = !(await this.safeDeployed(chainId));
59
+ const rawUserOp = await this.safePack.buildUserOp(tx, this.address, gasFees, this.setup, safeNotDeployed, this.safeSaltNonce);
60
+ const paymasterData = await bundler.getPaymasterData(rawUserOp, usePaymaster, safeNotDeployed);
70
61
  const unsignedUserOp = { ...rawUserOp, ...paymasterData };
71
62
  return unsignedUserOp;
72
63
  }
73
64
  async signTransaction(safeOpHash) {
74
- const signature = await getNearSignature(this.nearAdapter, safeOpHash);
65
+ const signature = await this.nearAdapter.sign(safeOpHash);
75
66
  return packSignature(signature);
76
67
  }
77
68
  async opHash(userOp) {
78
69
  return this.safePack.getOpHash(userOp);
79
70
  }
80
71
  async encodeSignRequest(tx) {
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
- }
85
72
  const unsignedUserOp = await this.buildTransaction({
73
+ chainId: tx.chainId,
86
74
  transactions: [
87
75
  {
88
76
  to: tx.to,
@@ -103,16 +91,27 @@ export class TransactionManager {
103
91
  evmMessage: JSON.stringify(unsignedUserOp),
104
92
  };
105
93
  }
106
- async executeTransaction(userOp) {
107
- const userOpHash = await this.bundler.sendUserOperation(userOp);
94
+ async executeTransaction(chainId, userOp) {
95
+ const bundler = this.bundlerForChainId(chainId);
96
+ const userOpHash = await bundler.sendUserOperation(userOp);
108
97
  console.log("UserOp Hash", userOpHash);
109
- const userOpReceipt = await this.bundler.getUserOpReceipt(userOpHash);
98
+ const userOpReceipt = await bundler.getUserOpReceipt(userOpHash);
110
99
  console.log("userOp Receipt", userOpReceipt);
111
100
  // Update safeNotDeployed after the first transaction
112
- this._safeNotDeployed =
113
- (await this.provider.getCode(this.address)) === "0x";
101
+ this.safeDeployed(chainId);
114
102
  return userOpReceipt;
115
103
  }
104
+ async safeDeployed(chainId) {
105
+ if (chainId in this.deployedChains) {
106
+ return true;
107
+ }
108
+ const provider = Network.fromChainId(chainId).client;
109
+ const deployed = (await provider.getCode({ address: this.address })) !== "0x";
110
+ if (deployed) {
111
+ this.deployedChains.add(chainId);
112
+ }
113
+ return deployed;
114
+ }
116
115
  addOwnerTx(address) {
117
116
  return {
118
117
  to: this.address,
@@ -120,12 +119,27 @@ export class TransactionManager {
120
119
  data: this.safePack.singleton.interface.encodeFunctionData("addOwnerWithThreshold", [address, 1]),
121
120
  };
122
121
  }
123
- async safeSufficientlyFunded(transactions, gasCost) {
122
+ async safeSufficientlyFunded(chainId, transactions, gasCost) {
124
123
  const txValue = transactions.reduce((acc, tx) => acc + BigInt(tx.value), 0n);
125
124
  if (txValue + gasCost === 0n) {
126
125
  return true;
127
126
  }
128
- const safeBalance = await this.getSafeBalance();
127
+ const safeBalance = await this.getBalance(chainId);
129
128
  return txValue + gasCost < safeBalance;
130
129
  }
130
+ async broadcastEvm(chainId, outcome, unsignedUserOp) {
131
+ const signature = packSignature(serializeSignature(signatureFromOutcome(outcome)));
132
+ try {
133
+ return {
134
+ signature,
135
+ receipt: await this.executeTransaction(chainId, {
136
+ ...unsignedUserOp,
137
+ signature,
138
+ }),
139
+ };
140
+ }
141
+ catch (error) {
142
+ throw new Error(`Failed EVM broadcast: ${error instanceof Error ? error.message : String(error)}`);
143
+ }
144
+ }
131
145
  }
@@ -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/esm/types.js CHANGED
@@ -1 +1,5 @@
1
- export {};
1
+ export var OperationType;
2
+ (function (OperationType) {
3
+ OperationType[OperationType["Call"] = 0] = "Call";
4
+ OperationType[OperationType["DelegateCall"] = 1] = "DelegateCall";
5
+ })(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/esm/util.js CHANGED
@@ -1,18 +1,18 @@
1
- import { ethers } from "ethers";
2
- export const PLACEHOLDER_SIG = ethers.solidityPacked(["uint48", "uint48"], [0, 0]);
3
- export const packGas = (hi, lo) => ethers.solidityPacked(["uint128", "uint128"], [hi, lo]);
1
+ import { concatHex, encodePacked, toHex } from "viem";
2
+ export const PLACEHOLDER_SIG = encodePacked(["uint48", "uint48"], [0, 0]);
3
+ export const packGas = (hi, lo) => encodePacked(["uint128", "uint128"], [BigInt(hi), BigInt(lo)]);
4
4
  export function packSignature(signature, validFrom = 0, validTo = 0) {
5
- return ethers.solidityPacked(["uint48", "uint48", "bytes"], [validFrom, validTo, signature]);
5
+ return encodePacked(["uint48", "uint48", "bytes"], [validFrom, validTo, signature]);
6
6
  }
7
7
  export function packPaymasterData(data) {
8
- return data.paymaster
9
- ? ethers.hexlify(ethers.concat([
8
+ return (data.paymaster
9
+ ? concatHex([
10
10
  data.paymaster,
11
- ethers.toBeHex(data.paymasterVerificationGasLimit || "0x", 16),
12
- ethers.toBeHex(data.paymasterPostOpGasLimit || "0x", 16),
11
+ toHex(BigInt(data.paymasterVerificationGasLimit || 0n), { size: 16 }),
12
+ toHex(BigInt(data.paymasterPostOpGasLimit || 0n), { size: 16 }),
13
13
  data.paymasterData || "0x",
14
- ]))
15
- : "0x";
14
+ ])
15
+ : "0x");
16
16
  }
17
17
  export function containsValue(transactions) {
18
18
  return transactions.some((tx) => tx.value !== "0");