@biconomy/abstractjs
Version:
SDK for Biconomy integration with support for account abstraction, smart accounts, ERC-4337.
99 lines • 3.96 kB
JavaScript
import { isHex, pad, publicActions, toFunctionSelector, toHex } from "viem";
import { ERROR_MESSAGES } from "../../account/index.js";
/**
* Parses a reference value into a 32-byte hex string.
* Handles various input types including Ethereum addresses, numbers, booleans, and raw hex values.
*
* @param referenceValue - The value to convert to hex
* @returns A 32-byte hex string (66 characters including '0x' prefix)
*
* @throws {Error} If the resulting hex string is invalid or not 32 bytes
*/
export function parseReferenceValue(referenceValue) {
let result;
// Handle 20-byte Ethereum address
if (isHex(referenceValue) && referenceValue.length === 42) {
// Remove '0x' prefix, pad to 32 bytes (64 characters) on the left, then add '0x' prefix back
result = `0x${"0".repeat(24)}${referenceValue.slice(2)}`;
}
else if (referenceValue?.raw) {
result = referenceValue?.raw;
}
else if (typeof referenceValue === "bigint") {
result = pad(toHex(referenceValue), { size: 32 });
}
else if (typeof referenceValue === "number") {
result = pad(toHex(BigInt(referenceValue)), { size: 32 });
}
else if (typeof referenceValue === "boolean") {
result = pad(toHex(referenceValue), { size: 32 });
}
else if (isHex(referenceValue)) {
// review
result = referenceValue;
}
else if (typeof referenceValue === "string") {
result = pad(referenceValue, { size: 32 });
}
else {
// (typeof referenceValue === "object")
result = pad(toHex(referenceValue), { size: 32 });
}
if (!isHex(result) || result.length !== 66) {
throw new Error(ERROR_MESSAGES.INVALID_HEX);
}
return result;
}
/**
* Extracts and validates the active module from a client's account.
*
* @param client - The viem Client instance with an optional modular smart account
* @returns The active module from the account
*
* @throws {Error} If no module is currently activated
*/
export const parseModule = (client) => {
const activeModule = client?.account?.getModule();
if (!activeModule) {
throw new Error(ERROR_MESSAGES.MODULE_NOT_ACTIVATED);
}
return activeModule;
};
export const isPermitSupported = async (walletClient, tokenAddress) => {
try {
const client = walletClient.extend(publicActions);
// Define all selectors
const permitSelector = toFunctionSelector("permit(address,address,uint256,uint256,uint8,bytes32,bytes32)");
const domainSeparatorSelector = "0x3644e515"; // keccak256("DOMAIN_SEPARATOR()")
const noncesSelector = "0x7ecebe00"; // keccak256("nonces(address)")
// Helper function to check function existence
const checkPermitEnabled = async (selector, padding = "") => {
return client
.call({
to: tokenAddress,
data: `${selector}${padding}`
})
.then(() => true)
.catch((error) => {
// For permit function, we check if it's a revert due to params, not function missing
if (selector === permitSelector) {
return (error.message.includes("revert") &&
!error.message.includes("function selector"));
}
return false;
});
};
// Create the calls to check for each function
const [hasPermit, hasDomainSeparator, hasNonces] = await Promise.all([
checkPermitEnabled(permitSelector, "0".repeat(64)),
checkPermitEnabled(domainSeparatorSelector),
checkPermitEnabled(noncesSelector, `000000000000000000000000${"0".repeat(40)}`)
]);
return hasPermit && hasDomainSeparator && hasNonces;
}
catch (err) {
console.error("Error checking permit support:", err);
return false;
}
};
//# sourceMappingURL=Helpers.js.map