near-safe
Version:
An SDK for controlling Ethereum Smart Accounts via ERC4337 from a Near Account.
84 lines (83 loc) • 3.12 kB
JavaScript
import { isEIP712TypedData } from "near-ca";
import { isAddress, isHex } from "viem";
export const isUserOperation = (data) => {
if (typeof data !== "object" || data === null)
return false;
const candidate = data;
// Required fields
const hasRequiredFields = "sender" in candidate &&
"nonce" in candidate &&
"callData" in candidate &&
"maxPriorityFeePerGas" in candidate &&
"maxFeePerGas" in candidate &&
"verificationGasLimit" in candidate &&
"callGasLimit" in candidate &&
"preVerificationGas" in candidate;
if (!hasRequiredFields)
return false;
// Type checks for required fields
const hasValidRequiredTypes = typeof candidate.sender === "string" &&
isAddress(candidate.sender) &&
typeof candidate.nonce === "string" &&
isHex(candidate.callData) &&
isHex(candidate.maxPriorityFeePerGas) &&
isHex(candidate.maxFeePerGas) &&
isHex(candidate.verificationGasLimit) &&
isHex(candidate.callGasLimit) &&
isHex(candidate.preVerificationGas);
if (!hasValidRequiredTypes)
return false;
// Optional fields type checks
if ("factory" in candidate && candidate.factory !== undefined) {
if (typeof candidate.factory !== "string" || !isAddress(candidate.factory))
return false;
}
if ("factoryData" in candidate && candidate.factoryData !== undefined) {
if (!isHex(candidate.factoryData))
return false;
}
if ("signature" in candidate && candidate.signature !== undefined) {
if (!isHex(candidate.signature))
return false;
}
if ("paymaster" in candidate && candidate.paymaster !== undefined) {
if (typeof candidate.paymaster !== "string" ||
!isAddress(candidate.paymaster))
return false;
}
if ("paymasterData" in candidate && candidate.paymasterData !== undefined) {
if (!isHex(candidate.paymasterData))
return false;
}
if ("paymasterVerificationGasLimit" in candidate &&
candidate.paymasterVerificationGasLimit !== undefined) {
if (!isHex(candidate.paymasterVerificationGasLimit))
return false;
}
if ("paymasterPostOpGasLimit" in candidate &&
candidate.paymasterPostOpGasLimit !== undefined) {
if (!isHex(candidate.paymasterPostOpGasLimit))
return false;
}
return true;
};
export const parseWithTypeGuard = (data, typeGuard) => {
// Case 1: Already the correct type
if (typeGuard(data)) {
return data;
}
// Case 2: Stringified data
if (typeof data === "string") {
try {
const parsed = JSON.parse(data);
return typeGuard(parsed) ? parsed : null;
}
catch (error) {
return null;
}
}
// Neither valid type nor valid stringified type
return null;
};
export const parseUserOperation = (data) => parseWithTypeGuard(data, isUserOperation);
export const parseEip712TypedData = (data) => parseWithTypeGuard(data, isEIP712TypedData);