near-safe 0.3.1 → 0.4.0

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