near-safe 0.8.8 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. package/dist/cjs/decode/explain.d.ts +38 -0
  2. package/dist/cjs/decode/explain.js +97 -0
  3. package/dist/cjs/decode/index.d.ts +2 -8
  4. package/dist/cjs/decode/index.js +16 -50
  5. package/dist/cjs/decode/sign-request.d.ts +8 -0
  6. package/dist/cjs/decode/sign-request.js +44 -0
  7. package/dist/cjs/decode/util.d.ts +0 -10
  8. package/dist/cjs/index.d.ts +1 -1
  9. package/dist/cjs/index.js +2 -3
  10. package/dist/cjs/lib/bundler.d.ts +7 -2
  11. package/dist/cjs/lib/bundler.js +8 -12
  12. package/dist/cjs/lib/safe-message.d.ts +1 -3
  13. package/dist/cjs/lib/safe-message.js +0 -30
  14. package/dist/cjs/near-safe.js +2 -2
  15. package/dist/cjs/types/guards.d.ts +6 -0
  16. package/dist/cjs/types/guards.js +90 -0
  17. package/dist/cjs/{types.d.ts → types/index.d.ts} +5 -9
  18. package/dist/cjs/types/index.js +28 -0
  19. package/dist/cjs/util.d.ts +2 -1
  20. package/dist/cjs/util.js +23 -2
  21. package/dist/esm/decode/explain.d.ts +38 -0
  22. package/dist/esm/decode/explain.js +91 -0
  23. package/dist/esm/decode/index.d.ts +2 -8
  24. package/dist/esm/decode/index.js +2 -49
  25. package/dist/esm/decode/sign-request.d.ts +8 -0
  26. package/dist/esm/decode/sign-request.js +41 -0
  27. package/dist/esm/decode/util.d.ts +0 -10
  28. package/dist/esm/index.d.ts +1 -1
  29. package/dist/esm/index.js +1 -1
  30. package/dist/esm/lib/bundler.d.ts +7 -2
  31. package/dist/esm/lib/bundler.js +9 -13
  32. package/dist/esm/lib/safe-message.d.ts +1 -3
  33. package/dist/esm/lib/safe-message.js +1 -29
  34. package/dist/esm/near-safe.js +2 -2
  35. package/dist/esm/types/guards.d.ts +6 -0
  36. package/dist/esm/types/guards.js +83 -0
  37. package/dist/esm/{types.d.ts → types/index.d.ts} +5 -9
  38. package/dist/esm/{types.js → types/index.js} +1 -0
  39. package/dist/esm/util.d.ts +2 -1
  40. package/dist/esm/util.js +22 -2
  41. package/package.json +2 -2
  42. package/dist/cjs/types.js +0 -13
package/dist/cjs/util.js CHANGED
@@ -11,6 +11,7 @@ exports.saltNonceFromMessage = saltNonceFromMessage;
11
11
  exports.signatureFromTxHash = signatureFromTxHash;
12
12
  exports.raceToFirstResolve = raceToFirstResolve;
13
13
  exports.assertUnique = assertUnique;
14
+ exports.userOpTransactionCost = userOpTransactionCost;
14
15
  const near_ca_1 = require("near-ca");
15
16
  const viem_1 = require("viem");
16
17
  const constants_1 = require("./constants");
@@ -31,13 +32,13 @@ function packPaymasterData(data) {
31
32
  : "0x");
32
33
  }
33
34
  function containsValue(transactions) {
34
- return transactions.some((tx) => tx.value !== "0");
35
+ return transactions.some((tx) => BigInt(tx.value) !== 0n);
35
36
  }
36
37
  async function isContract(address, chainId) {
37
38
  return (await getClient(chainId).getCode({ address })) !== undefined;
38
39
  }
39
40
  function getClient(chainId) {
40
- // TODO(bh2smith)
41
+ // TODO(bh2smith): Update defailt client URL in viem for sepolia.
41
42
  if (chainId === 11155111) {
42
43
  return (0, viem_1.createPublicClient)({ transport: (0, viem_1.http)(constants_1.DEFAULT_SETUP_RPC) });
43
44
  }
@@ -144,3 +145,23 @@ function assertUnique(iterable, errorMessage = "The collection contains more tha
144
145
  throw new Error(errorMessage);
145
146
  }
146
147
  }
148
+ function userOpTransactionCost(userOp) {
149
+ // Convert values from hex to decimal
150
+ const preVerificationGas = BigInt(userOp.preVerificationGas);
151
+ const verificationGasLimit = BigInt(userOp.verificationGasLimit);
152
+ const callGasLimit = BigInt(userOp.callGasLimit);
153
+ const paymasterVerificationGasLimit = BigInt(userOp.paymasterVerificationGasLimit || "0x0");
154
+ const paymasterPostOpGasLimit = BigInt(userOp.paymasterPostOpGasLimit || "0x0");
155
+ // Sum total gas
156
+ const totalGasUsed = preVerificationGas +
157
+ verificationGasLimit +
158
+ callGasLimit +
159
+ paymasterVerificationGasLimit +
160
+ paymasterPostOpGasLimit;
161
+ // Convert maxFeePerGas from hex to decimal
162
+ const maxFeePerGas = BigInt(userOp.maxFeePerGas);
163
+ // Calculate total cost in wei
164
+ const totalCostInWei = totalGasUsed * maxFeePerGas;
165
+ // Convert to Ether for a human-readable value
166
+ return totalCostInWei;
167
+ }
@@ -0,0 +1,38 @@
1
+ import { DecodedTxData, SafeEncodedSignRequest } from "../types";
2
+ /**
3
+ * Explain a Safe Signature Request.
4
+ * @param signRequest - The Safe Signature Request to explain.
5
+ * @returns The decoded transaction data as stringified JSON or null if there was an error.
6
+ */
7
+ export declare function explainSignRequest(signRequest: SafeEncodedSignRequest): Promise<string>;
8
+ /**
9
+ * Represents a parameter in a decoded contract call.
10
+ */
11
+ interface DecodedParameter {
12
+ /** The parameter name from the contract ABI */
13
+ name: string;
14
+ /** The parameter type (e.g., 'address', 'uint256') */
15
+ type: string;
16
+ /** The actual value of the parameter */
17
+ value: string;
18
+ }
19
+ /**
20
+ * Represents a successful response from the Safe transaction decoder.
21
+ */
22
+ interface FunctionSignature {
23
+ /** The name of the contract method that was called */
24
+ method: string;
25
+ /** Array of decoded parameters from the function call */
26
+ parameters: DecodedParameter[];
27
+ }
28
+ /**
29
+ * Decode a transaction using the Safe Decoder API. According to this spec:
30
+ * https://safe-transaction-sepolia.safe.global/#/data-decoder/data_decoder_create
31
+ * @param data - The transaction data to decode.
32
+ * @param to - The address of the contract that was called.
33
+ * @param chainId - The chain ID of the transaction.
34
+ * @returns The decoded transaction data or null if there was an error.
35
+ */
36
+ export declare function safeDecodeTx(data: string, to: string, chainId: number): Promise<FunctionSignature | null>;
37
+ export declare const formatEvmData: (decodedEvmData: DecodedTxData, functionSignatures?: (FunctionSignature | null)[]) => string;
38
+ export {};
@@ -0,0 +1,91 @@
1
+ import { Network } from "near-ca";
2
+ import { decodeTxData } from ".";
3
+ /**
4
+ * Explain a Safe Signature Request.
5
+ * @param signRequest - The Safe Signature Request to explain.
6
+ * @returns The decoded transaction data as stringified JSON or null if there was an error.
7
+ */
8
+ export async function explainSignRequest(signRequest) {
9
+ // Decode the Signature Request
10
+ const decodedEvmData = decodeTxData(signRequest);
11
+ // Decode the function signatures
12
+ const functionSignatures = await Promise.all(decodedEvmData.transactions.map((tx) => safeDecodeTx(tx.data, tx.to, decodedEvmData.chainId)));
13
+ // Format the decoded data
14
+ return formatEvmData(decodedEvmData, functionSignatures);
15
+ }
16
+ const SAFE_NETWORKS = {
17
+ 1: "mainnet", // Ethereum Mainnet
18
+ 10: "optimism", // Optimism Mainnet
19
+ 56: "binance", // Binance Smart Chain Mainnet
20
+ 97: "bsc-testnet", // Binance Smart Chain Testnet
21
+ 100: "gnosis-chain", // Gnosis Chain (formerly xDAI)
22
+ 137: "polygon", // Polygon Mainnet
23
+ 250: "fantom", // Fantom Mainnet
24
+ 288: "boba", // Boba Network Mainnet
25
+ 1284: "moonbeam", // Moonbeam (Polkadot)
26
+ 1285: "moonriver", // Moonriver (Kusama)
27
+ 4002: "fantom-testnet", // Fantom Testnet
28
+ 42161: "arbitrum", // Arbitrum One Mainnet
29
+ 43113: "avalanche-fuji", // Avalanche Fuji Testnet
30
+ 43114: "avalanche", // Avalanche Mainnet
31
+ 80001: "polygon-mumbai", // Polygon Mumbai Testnet
32
+ 8453: "base", // Base Mainnet
33
+ 11155111: "sepolia", // Sepolia Testnet
34
+ 1666600000: "harmony", // Harmony Mainnet
35
+ 1666700000: "harmony-testnet", // Harmony Testnet
36
+ 1313161554: "aurora", // Aurora Mainnet (NEAR)
37
+ 1313161555: "aurora-testnet", // Aurora Testnet (NEAR)
38
+ };
39
+ /**
40
+ * Decode a transaction using the Safe Decoder API. According to this spec:
41
+ * https://safe-transaction-sepolia.safe.global/#/data-decoder/data_decoder_create
42
+ * @param data - The transaction data to decode.
43
+ * @param to - The address of the contract that was called.
44
+ * @param chainId - The chain ID of the transaction.
45
+ * @returns The decoded transaction data or null if there was an error.
46
+ */
47
+ export async function safeDecodeTx(data, to, chainId) {
48
+ try {
49
+ const network = SAFE_NETWORKS[chainId] || SAFE_NETWORKS[1];
50
+ const response = await fetch(`https://safe-transaction-${network}.safe.global/api/v1/data-decoder/`, {
51
+ method: "POST",
52
+ headers: {
53
+ "Content-Type": "application/json",
54
+ accept: "application/json",
55
+ },
56
+ body: JSON.stringify({ data, to }),
57
+ });
58
+ // Handle different response status codes
59
+ if (response.status === 404) {
60
+ console.warn("Cannot find function selector to decode data");
61
+ return null;
62
+ }
63
+ if (response.status === 422) {
64
+ const errorData = (await response.json());
65
+ console.error("Invalid data:", errorData.message, errorData.arguments);
66
+ return null;
67
+ }
68
+ if (!response.ok) {
69
+ console.error(`Unexpected response status: ${response.status}`);
70
+ return null;
71
+ }
72
+ return (await response.json());
73
+ }
74
+ catch (error) {
75
+ const message = error instanceof Error ? error.message : String(error);
76
+ console.error("Error decoding transaction:", message);
77
+ return null;
78
+ }
79
+ }
80
+ export const formatEvmData = (decodedEvmData, functionSignatures = []) => {
81
+ const formatted = {
82
+ ...decodedEvmData,
83
+ network: Network.fromChainId(decodedEvmData.chainId).name,
84
+ functionSignatures,
85
+ };
86
+ return JSON.stringify(formatted, bigIntReplacer, 2);
87
+ };
88
+ /**
89
+ * Replaces bigint values with their string representation.
90
+ */
91
+ const bigIntReplacer = (_, value) => typeof value === "bigint" ? value.toString() : value;
@@ -1,8 +1,2 @@
1
- import { DecodedTxData, SafeEncodedSignRequest } from "../types";
2
- /**
3
- * Decodes transaction data for a given EVM transaction and extracts relevant details.
4
- *
5
- * @param {EvmTransactionData} data - The raw transaction data to be decoded.
6
- * @returns {DecodedTxData} - An object containing the chain ID, estimated cost, and a list of decoded meta-transactions.
7
- */
8
- export declare function decodeTxData({ evmMessage, chainId, }: Omit<SafeEncodedSignRequest, "hashToSign">): DecodedTxData;
1
+ export * from "./explain";
2
+ export * from "./sign-request";
@@ -1,49 +1,2 @@
1
- import { isRlpHex, isTransactionSerializable } from "../lib/safe-message";
2
- import { decodeRlpHex, decodeTransactionSerializable, decodeTypedData, decodeUserOperation, } from "./util";
3
- /**
4
- * Decodes transaction data for a given EVM transaction and extracts relevant details.
5
- *
6
- * @param {EvmTransactionData} data - The raw transaction data to be decoded.
7
- * @returns {DecodedTxData} - An object containing the chain ID, estimated cost, and a list of decoded meta-transactions.
8
- */
9
- export function decodeTxData({ evmMessage, chainId, }) {
10
- const data = evmMessage;
11
- if (isRlpHex(evmMessage)) {
12
- return decodeRlpHex(chainId, evmMessage);
13
- }
14
- if (isTransactionSerializable(data)) {
15
- return decodeTransactionSerializable(chainId, data);
16
- }
17
- if (typeof data !== "string") {
18
- return decodeTypedData(chainId, data);
19
- }
20
- try {
21
- // Stringified UserOperation.
22
- const userOp = JSON.parse(data);
23
- return decodeUserOperation(chainId, userOp);
24
- }
25
- catch (error) {
26
- if (error instanceof SyntaxError) {
27
- // Raw message string.
28
- return {
29
- chainId,
30
- costEstimate: "0",
31
- transactions: [],
32
- message: data,
33
- };
34
- }
35
- else {
36
- // TODO: This shouldn't happen anymore and can probably be reverted.
37
- // We keep it here now, because near-ca might not have adapted its router.
38
- console.warn("Failed UserOp Parsing, try TypedData Parsing", error);
39
- try {
40
- const typedData = JSON.parse(data);
41
- return decodeTypedData(chainId, typedData);
42
- }
43
- catch (error) {
44
- const message = error instanceof Error ? error.message : String(error);
45
- throw new Error(`decodeTxData: Unexpected error - ${message}`);
46
- }
47
- }
48
- }
49
- }
1
+ export * from "./explain";
2
+ export * from "./sign-request";
@@ -0,0 +1,8 @@
1
+ import { DecodedTxData, SafeEncodedSignRequest } from "../types";
2
+ /**
3
+ * Decodes transaction data for a given EVM transaction and extracts relevant details.
4
+ *
5
+ * @param {EvmTransactionData} data - The raw transaction data to be decoded.
6
+ * @returns {DecodedTxData} - An object containing the chain ID, estimated cost, and a list of decoded meta-transactions.
7
+ */
8
+ export declare function decodeTxData({ evmMessage, chainId, }: Omit<SafeEncodedSignRequest, "hashToSign">): DecodedTxData;
@@ -0,0 +1,41 @@
1
+ import { isRlpHex, isTransactionSerializable } from "near-ca";
2
+ import { parseEip712TypedData, parseUserOperation, } from "../types";
3
+ import { decodeRlpHex, decodeTransactionSerializable, decodeTypedData, decodeUserOperation, } from "./util";
4
+ /**
5
+ * Decodes transaction data for a given EVM transaction and extracts relevant details.
6
+ *
7
+ * @param {EvmTransactionData} data - The raw transaction data to be decoded.
8
+ * @returns {DecodedTxData} - An object containing the chain ID, estimated cost, and a list of decoded meta-transactions.
9
+ */
10
+ export function decodeTxData({ evmMessage, chainId, }) {
11
+ const data = evmMessage;
12
+ if (isRlpHex(evmMessage)) {
13
+ return decodeRlpHex(chainId, evmMessage);
14
+ }
15
+ if (isTransactionSerializable(data)) {
16
+ return decodeTransactionSerializable(chainId, data);
17
+ }
18
+ const parsedTypedData = parseEip712TypedData(data);
19
+ if (parsedTypedData) {
20
+ return decodeTypedData(chainId, parsedTypedData);
21
+ }
22
+ const userOp = parseUserOperation(data);
23
+ if (userOp) {
24
+ return decodeUserOperation(chainId, userOp);
25
+ }
26
+ // At this point we are certain that the data is a string.
27
+ // Typescript would disagree here because of the EIP712TypedData possibility that remains.
28
+ // However this is captured (indirectly) by parseEip712TypedData above.
29
+ // We check now if its a string and return a reasonable default (for the case of a raw message).
30
+ if (typeof data === "string") {
31
+ return {
32
+ chainId,
33
+ costEstimate: "0",
34
+ transactions: [],
35
+ message: data,
36
+ };
37
+ }
38
+ // Otherwise we have no idea what the data is and we throw.
39
+ console.warn("Unrecognized txData format,", chainId, data);
40
+ throw new Error(`decodeTxData: Invalid or unsupported message format ${data}`);
41
+ }
@@ -5,13 +5,3 @@ export declare function decodeTransactionSerializable(chainId: number, tx: Trans
5
5
  export declare function decodeRlpHex(chainId: number, tx: Hex): DecodedTxData;
6
6
  export declare function decodeTypedData(chainId: number, data: EIP712TypedData): DecodedTxData;
7
7
  export declare function decodeUserOperation(chainId: number, userOp: UserOperation): DecodedTxData;
8
- export declare enum OperationType {
9
- Call = 0,
10
- DelegateCall = 1
11
- }
12
- export interface MetaTransaction {
13
- readonly to: string;
14
- readonly value: string;
15
- readonly data: string;
16
- readonly operation?: OperationType;
17
- }
@@ -2,6 +2,6 @@ export * from "./near-safe";
2
2
  export * from "./types";
3
3
  export * from "./util";
4
4
  export * from "./constants";
5
- export { decodeTxData } from "./decode";
5
+ export * from "./decode";
6
6
  export * from "./lib/safe-message";
7
7
  export { Network, BaseTx, SignRequestData, populateTx, NetworkFields, signatureFromOutcome, signatureFromTxHash, requestRouter as mpcRequestRouter, EthTransactionParams, } from "near-ca";
package/dist/esm/index.js CHANGED
@@ -2,6 +2,6 @@ export * from "./near-safe";
2
2
  export * from "./types";
3
3
  export * from "./util";
4
4
  export * from "./constants";
5
- export { decodeTxData } from "./decode";
5
+ export * from "./decode";
6
6
  export * from "./lib/safe-message";
7
7
  export { Network, populateTx, signatureFromOutcome, signatureFromTxHash, requestRouter as mpcRequestRouter, } from "near-ca";
@@ -1,5 +1,5 @@
1
1
  import { Address, Hash, PublicClient, Transport } from "viem";
2
- import { GasPrices, PaymasterData, SponsorshipPolicyData, UnsignedUserOperation, UserOperation, UserOperationReceipt } from "../types";
2
+ import { GasPrices, PaymasterData, SponsorshipPolicyData, UnsignedUserOperation, UserOperation, UserOperationGas, UserOperationReceipt } from "../types";
3
3
  type SponsorshipPolicy = {
4
4
  sponsorshipPolicyId: string;
5
5
  };
@@ -9,6 +9,11 @@ type BundlerRpcSchema = [
9
9
  Parameters: [UnsignedUserOperation, Address, SponsorshipPolicy];
10
10
  ReturnType: PaymasterData;
11
11
  },
12
+ {
13
+ Method: "eth_estimateUserOperationGas";
14
+ Parameters: [UnsignedUserOperation, Address];
15
+ ReturnType: UserOperationGas;
16
+ },
12
17
  {
13
18
  Method: "eth_sendUserOperation";
14
19
  Parameters: [UserOperation, Address];
@@ -31,7 +36,7 @@ export declare class Erc4337Bundler {
31
36
  apiKey: string;
32
37
  chainId: number;
33
38
  constructor(entryPointAddress: Address, apiKey: string, chainId: number);
34
- getPaymasterData(rawUserOp: UnsignedUserOperation, safeNotDeployed: boolean, sponsorshipPolicy?: string): Promise<PaymasterData>;
39
+ getPaymasterData(rawUserOp: UnsignedUserOperation, sponsorshipPolicy?: string): Promise<PaymasterData>;
35
40
  sendUserOperation(userOp: UserOperation): Promise<Hash>;
36
41
  getGasPrice(): Promise<GasPrices>;
37
42
  getUserOpReceipt(userOpHash: Hash): Promise<UserOperationReceipt>;
@@ -1,4 +1,4 @@
1
- import { createPublicClient, http, rpcSchema, toHex, RpcError, HttpRequestError, } from "viem";
1
+ import { createPublicClient, http, rpcSchema, RpcError, HttpRequestError, } from "viem";
2
2
  import { PLACEHOLDER_SIG } from "../util";
3
3
  function bundlerUrl(chainId, apikey) {
4
4
  return `https://api.pimlico.io/v2/${chainId}/rpc?apikey=${apikey}`;
@@ -17,20 +17,24 @@ export class Erc4337Bundler {
17
17
  rpcSchema: rpcSchema(),
18
18
  });
19
19
  }
20
- async getPaymasterData(rawUserOp, safeNotDeployed, sponsorshipPolicy) {
21
- // TODO: Keep this option out of the bundler
20
+ async getPaymasterData(rawUserOp, sponsorshipPolicy) {
21
+ const userOp = { ...rawUserOp, signature: PLACEHOLDER_SIG };
22
22
  if (sponsorshipPolicy) {
23
23
  console.log("Requesting paymaster data...");
24
24
  return handleRequest(() => this.client.request({
25
25
  method: "pm_sponsorUserOperation",
26
26
  params: [
27
- { ...rawUserOp, signature: PLACEHOLDER_SIG },
27
+ userOp,
28
28
  this.entryPointAddress,
29
29
  { sponsorshipPolicyId: sponsorshipPolicy },
30
30
  ],
31
31
  }));
32
32
  }
33
- return defaultPaymasterData(safeNotDeployed);
33
+ console.log("Estimating user operation gas...");
34
+ return handleRequest(() => this.client.request({
35
+ method: "eth_estimateUserOperationGas",
36
+ params: [userOp, this.entryPointAddress],
37
+ }));
34
38
  }
35
39
  async sendUserOperation(userOp) {
36
40
  return handleRequest(() => this.client.request({
@@ -93,14 +97,6 @@ async function handleRequest(clientMethod) {
93
97
  throw new Error(`Bundler Request: ${message}`);
94
98
  }
95
99
  }
96
- // TODO(bh2smith) Should probably get reasonable estimates here:
97
- const defaultPaymasterData = (safeNotDeployed) => {
98
- return {
99
- verificationGasLimit: toHex(safeNotDeployed ? 500000 : 100000),
100
- callGasLimit: toHex(100000),
101
- preVerificationGas: toHex(100000),
102
- };
103
- };
104
100
  export function stripApiKey(error) {
105
101
  const message = error instanceof Error ? error.message : String(error);
106
102
  return message.replace(/(apikey=)[^\s&]+/, "$1***");
@@ -1,6 +1,6 @@
1
1
  import { type SafeInfo } from "@safe-global/safe-gateway-typescript-sdk";
2
2
  import { EIP712TypedData } from "near-ca";
3
- import { Hash, Hex, TransactionSerializable } from "viem";
3
+ import { Hash } from "viem";
4
4
  export type DecodedSafeMessage = {
5
5
  decodedMessage: string | EIP712TypedData;
6
6
  safeMessageMessage: string;
@@ -20,5 +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 isTransactionSerializable(data: unknown): data is TransactionSerializable;
24
- export declare function isRlpHex(data: unknown): data is Hex;
@@ -1,5 +1,5 @@
1
1
  import { gte } from "semver";
2
- import { fromHex, hashMessage, hashTypedData, isHex, parseTransaction, serializeTransaction, } from "viem";
2
+ import { fromHex, hashMessage, hashTypedData, isHex, } from "viem";
3
3
  /*
4
4
  * From v1.3.0, EIP-1271 support was moved to the CompatibilityFallbackHandler.
5
5
  * Also 1.3.0 introduces the chainId in the domain part of the SafeMessage
@@ -79,33 +79,5 @@ export function decodeSafeMessage(message, safe) {
79
79
  safeMessageHash: generateSafeMessageHash(safe, decodedMessage),
80
80
  };
81
81
  }
82
- // const isEIP712TypedData = (obj: any): obj is EIP712TypedData => {
83
- // return (
84
- // typeof obj === "object" &&
85
- // obj != null &&
86
- // "domain" in obj &&
87
- // "types" in obj &&
88
- // "message" in obj
89
- // );
90
- // };
91
82
  // export const isBlindSigningPayload = (obj: EIP712TypedData | string): boolean =>
92
83
  // !isEIP712TypedData(obj) && isHash(obj);
93
- // Cheeky attempt to serialize. return true if successful!
94
- export function isTransactionSerializable(data) {
95
- try {
96
- serializeTransaction(data);
97
- return true;
98
- }
99
- catch (error) {
100
- return false;
101
- }
102
- }
103
- export function isRlpHex(data) {
104
- try {
105
- parseTransaction(data);
106
- return true;
107
- }
108
- catch (error) {
109
- return false;
110
- }
111
- }
@@ -103,7 +103,7 @@ export class NearSafe {
103
103
  // Build Singular MetaTransaction for Multisend from transaction list.
104
104
  const tx = transactions.length > 1 ? encodeMulti(transactions) : transactions[0];
105
105
  const rawUserOp = await this.safePack.buildUserOp(nonce, tx, this.address, gasFees.fast, this.setup, !safeDeployed, this.safeSaltNonce);
106
- const paymasterData = await bundler.getPaymasterData(rawUserOp, !safeDeployed, sponsorshipPolicy);
106
+ const paymasterData = await bundler.getPaymasterData(rawUserOp, sponsorshipPolicy);
107
107
  const unsignedUserOp = { ...rawUserOp, ...paymasterData };
108
108
  return unsignedUserOp;
109
109
  }
@@ -239,7 +239,7 @@ export class NearSafe {
239
239
  async removeOwnerTx(chainId, address) {
240
240
  return {
241
241
  to: this.address,
242
- value: "0",
242
+ value: "0x00",
243
243
  data: await this.safePack.removeOwnerData(chainId, this.address, address),
244
244
  };
245
245
  }
@@ -0,0 +1,6 @@
1
+ import { EIP712TypedData } from "near-ca";
2
+ import { UserOperation } from ".";
3
+ export declare const isUserOperation: (data: unknown) => data is UserOperation;
4
+ export declare const parseWithTypeGuard: <T>(data: unknown, typeGuard: (value: unknown) => value is T) => T | null;
5
+ export declare const parseUserOperation: (data: unknown) => UserOperation | null;
6
+ export declare const parseEip712TypedData: (data: unknown) => EIP712TypedData | null;
@@ -0,0 +1,83 @@
1
+ import { isEIP712TypedData } from "near-ca";
2
+ import { isAddress, isHex } from "viem";
3
+ export const isUserOperation = (data) => {
4
+ if (typeof data !== "object" || data === null)
5
+ return false;
6
+ const candidate = data;
7
+ // Required fields
8
+ const hasRequiredFields = "sender" in candidate &&
9
+ "nonce" in candidate &&
10
+ "callData" in candidate &&
11
+ "maxPriorityFeePerGas" in candidate &&
12
+ "maxFeePerGas" in candidate &&
13
+ "verificationGasLimit" in candidate &&
14
+ "callGasLimit" in candidate &&
15
+ "preVerificationGas" in candidate;
16
+ if (!hasRequiredFields)
17
+ return false;
18
+ // Type checks for required fields
19
+ const hasValidRequiredTypes = typeof candidate.sender === "string" &&
20
+ isAddress(candidate.sender) &&
21
+ typeof candidate.nonce === "string" &&
22
+ isHex(candidate.callData) &&
23
+ isHex(candidate.maxPriorityFeePerGas) &&
24
+ isHex(candidate.maxFeePerGas) &&
25
+ isHex(candidate.verificationGasLimit) &&
26
+ isHex(candidate.callGasLimit) &&
27
+ isHex(candidate.preVerificationGas);
28
+ if (!hasValidRequiredTypes)
29
+ return false;
30
+ // Optional fields type checks
31
+ if ("factory" in candidate && candidate.factory !== undefined) {
32
+ if (typeof candidate.factory !== "string" || !isAddress(candidate.factory))
33
+ return false;
34
+ }
35
+ if ("factoryData" in candidate && candidate.factoryData !== undefined) {
36
+ if (!isHex(candidate.factoryData))
37
+ return false;
38
+ }
39
+ if ("signature" in candidate && candidate.signature !== undefined) {
40
+ if (!isHex(candidate.signature))
41
+ return false;
42
+ }
43
+ if ("paymaster" in candidate && candidate.paymaster !== undefined) {
44
+ if (typeof candidate.paymaster !== "string" ||
45
+ !isAddress(candidate.paymaster))
46
+ return false;
47
+ }
48
+ if ("paymasterData" in candidate && candidate.paymasterData !== undefined) {
49
+ if (!isHex(candidate.paymasterData))
50
+ return false;
51
+ }
52
+ if ("paymasterVerificationGasLimit" in candidate &&
53
+ candidate.paymasterVerificationGasLimit !== undefined) {
54
+ if (!isHex(candidate.paymasterVerificationGasLimit))
55
+ return false;
56
+ }
57
+ if ("paymasterPostOpGasLimit" in candidate &&
58
+ candidate.paymasterPostOpGasLimit !== undefined) {
59
+ if (!isHex(candidate.paymasterPostOpGasLimit))
60
+ return false;
61
+ }
62
+ return true;
63
+ };
64
+ export const parseWithTypeGuard = (data, typeGuard) => {
65
+ // Case 1: Already the correct type
66
+ if (typeGuard(data)) {
67
+ return data;
68
+ }
69
+ // Case 2: Stringified data
70
+ if (typeof data === "string") {
71
+ try {
72
+ const parsed = JSON.parse(data);
73
+ return typeGuard(parsed) ? parsed : null;
74
+ }
75
+ catch (error) {
76
+ return null;
77
+ }
78
+ }
79
+ // Neither valid type nor valid stringified type
80
+ return null;
81
+ };
82
+ export const parseUserOperation = (data) => parseWithTypeGuard(data, isUserOperation);
83
+ export const parseEip712TypedData = (data) => parseWithTypeGuard(data, isEIP712TypedData);
@@ -1,5 +1,6 @@
1
1
  import { EIP712TypedData, EncodedSignRequest, FunctionCallTransaction, SignArgs } from "near-ca";
2
2
  import { Address, Hex, ParseAbi } from "viem";
3
+ export * from "./guards";
3
4
  /**
4
5
  * Represents a collection of Safe contract deployments, each with its own address and ABI.
5
6
  */
@@ -46,24 +47,20 @@ export interface UnsignedUserOperation {
46
47
  /**
47
48
  * Supported representation of a user operation for EntryPoint version 0.7, including gas limits and signature.
48
49
  */
49
- export interface UserOperation extends UnsignedUserOperation {
50
- /** The gas limit for verification of the operation. */
51
- verificationGasLimit: Hex;
52
- /** The gas limit for the execution of the operation call. */
53
- callGasLimit: Hex;
54
- /** The gas used before verification begins. */
55
- preVerificationGas: Hex;
50
+ export interface UserOperation extends UnsignedUserOperation, PaymasterData {
56
51
  /** Optional signature for the user operation. */
57
52
  signature?: Hex;
58
53
  }
59
54
  /**
60
55
  * Represents additional paymaster-related data for a user operation.
61
56
  */
62
- export interface PaymasterData {
57
+ export interface PaymasterData extends UserOperationGas {
63
58
  /** Optional paymaster address responsible for covering gas costs. */
64
59
  paymaster?: Address;
65
60
  /** Optional additional data required by the paymaster. */
66
61
  paymasterData?: Hex;
62
+ }
63
+ export interface UserOperationGas {
67
64
  /** The gas limit for paymaster verification. */
68
65
  paymasterVerificationGasLimit?: Hex;
69
66
  /** The gas limit for paymaster post-operation execution. */
@@ -270,4 +267,3 @@ export interface SpendingLimit {
270
267
  export interface ChainIds {
271
268
  allowlist: number[];
272
269
  }
273
- export {};
@@ -1,3 +1,4 @@
1
+ export * from "./guards";
1
2
  /**
2
3
  * Enum representing the type of operation in a meta-transaction.
3
4
  */
@@ -1,6 +1,6 @@
1
1
  import { SessionRequestParams } from "near-ca";
2
2
  import { Address, Hex, PublicClient } from "viem";
3
- import { PaymasterData, MetaTransaction } from "./types";
3
+ import { PaymasterData, MetaTransaction, UserOperation } from "./types";
4
4
  export declare const PLACEHOLDER_SIG: `0x${string}`;
5
5
  type IntLike = Hex | bigint | string | number;
6
6
  export declare const packGas: (hi: IntLike, lo: IntLike) => string;
@@ -38,4 +38,5 @@ export declare function signatureFromTxHash(txHash: string, accountId?: string):
38
38
  */
39
39
  export declare function raceToFirstResolve<T>(promises: Promise<T>[]): Promise<T>;
40
40
  export declare function assertUnique<T>(iterable: Iterable<T>, errorMessage?: string): void;
41
+ export declare function userOpTransactionCost(userOp: UserOperation): bigint;
41
42
  export {};