UNPKG

@biconomy/modules

Version:

This package provides different validation modules/plugins for ERC4337 compatible modular account

132 lines 7.13 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MultiChainValidationModule = void 0; const common_1 = require("@biconomy/common"); const ethers_1 = require("ethers"); const merkletreejs_1 = __importDefault(require("merkletreejs")); const Constants_1 = require("./utils/Constants"); const utils_1 = require("ethers/lib/utils"); const BaseValidationModule_1 = require("./BaseValidationModule"); const aa_core_1 = require("@alchemy/aa-core"); class MultiChainValidationModule extends BaseValidationModule_1.BaseValidationModule { constructor(moduleConfig) { super(moduleConfig); this.version = "V1_0_0"; } static async create(moduleConfig) { const instance = new MultiChainValidationModule(moduleConfig); if (moduleConfig.moduleAddress) { instance.moduleAddress = moduleConfig.moduleAddress; } else if (moduleConfig.version) { const moduleAddr = Constants_1.MULTICHAIN_VALIDATION_MODULE_ADDRESSES_BY_VERSION[moduleConfig.version]; if (!moduleAddr) { throw new Error(`Invalid version ${moduleConfig.version}`); } instance.moduleAddress = moduleAddr; instance.version = moduleConfig.version; } else { instance.moduleAddress = Constants_1.DEFAULT_MULTICHAIN_MODULE; // Note: in this case Version remains the default one } instance.signer = moduleConfig.signer; return instance; } getAddress() { return this.moduleAddress; } async getSigner() { return Promise.resolve(this.signer); } async getDummySignature() { const moduleAddress = ethers_1.ethers.utils.getAddress(this.getAddress()); const dynamicPart = moduleAddress.substring(2).padEnd(40, "0"); return `0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000${dynamicPart}000000000000000000000000000000000000000000000000000000000000004181d4b4981670cb18f99f0b4a66446df1bf5b204d24cfcb659bf38ba27a4359b5711649ec2423c5e1247245eba2964679b6a1dbb85c992ae40b9b00c6935b02ff1b00000000000000000000000000000000000000000000000000000000000000`; } // Note: other modules may need additional attributes to build init data async getInitData() { const ecdsaOwnerAddress = await this.signer.getAddress(); const moduleRegistryAbi = "function initForSmartAccount(address owner)"; const ecdsaModuleRegistryInterface = new ethers_1.ethers.utils.Interface([moduleRegistryAbi]); const ecdsaOwnershipInitData = ecdsaModuleRegistryInterface.encodeFunctionData("initForSmartAccount", [ecdsaOwnerAddress]); return ecdsaOwnershipInitData; } async signUserOpHash(userOpHash) { const sig = await this.signer.signMessage((0, utils_1.arrayify)(userOpHash)); common_1.Logger.log("ecdsa signature ", sig); return sig; } /** * Signs a message using the appropriate method based on the type of signer. * * @param {Bytes | string | Uint8Array} message - The message to be signed. * @returns {Promise<string>} A promise resolving to the signature or error message. * @throws {Error} If the signer type is invalid or unsupported. */ async signMessage(message) { if (this.signer instanceof aa_core_1.WalletClientSigner) { return super.signMessageWalletClientSigner(message, this.signer); } else if (this.signer instanceof ethers_1.Signer) { return super.signMessageSigner(message, this.signer); } else { throw new Error("Invalid signer type"); } } async signUserOps(multiChainUserOps) { var _a, _b, _c, _d; try { const leaves = []; // Iterate over each userOp and process them for (const multiChainOp of multiChainUserOps) { const validUntil = (_a = multiChainOp.validUntil) !== null && _a !== void 0 ? _a : 0; const validAfter = (_b = multiChainOp.validAfter) !== null && _b !== void 0 ? _b : 0; const leaf = (0, utils_1.hexConcat)([ (0, utils_1.hexZeroPad)(ethers_1.ethers.utils.hexlify(validUntil), 6), (0, utils_1.hexZeroPad)(ethers_1.ethers.utils.hexlify(validAfter), 6), (0, utils_1.hexZeroPad)((0, common_1.getUserOpHash)(multiChainOp.userOp, this.entryPointAddress, multiChainOp.chainId), 32), ]); leaves.push((0, utils_1.keccak256)(leaf)); } // Create a new Merkle tree using the leaves array const merkleTree = new merkletreejs_1.default(leaves, utils_1.keccak256, { sortPairs: true }); let multichainSignature = await this.signer.signMessage((0, utils_1.arrayify)(merkleTree.getHexRoot())); const potentiallyIncorrectV = parseInt(multichainSignature.slice(-2), 16); if (![27, 28].includes(potentiallyIncorrectV)) { const correctV = potentiallyIncorrectV + 27; multichainSignature = multichainSignature.slice(0, -2) + correctV.toString(16); } // Create an array to store updated userOps const updatedUserOps = []; common_1.Logger.log("merkle root ", merkleTree.getHexRoot()); for (let i = 0; i < leaves.length; i++) { const merkleProof = merkleTree.getHexProof(leaves[i]); common_1.Logger.log("merkle proof ", merkleProof); const validUntil = (_c = multiChainUserOps[i].validUntil) !== null && _c !== void 0 ? _c : 0; const validAfter = (_d = multiChainUserOps[i].validAfter) !== null && _d !== void 0 ? _d : 0; // Create the moduleSignature const moduleSignature = utils_1.defaultAbiCoder.encode(["uint48", "uint48", "bytes32", "bytes32[]", "bytes"], [validUntil, validAfter, merkleTree.getHexRoot(), merkleProof, multichainSignature]); // Note: Because accountV2 does not directly call this method. hence we need to add validation module address to the signature const signatureWithModuleAddress = utils_1.defaultAbiCoder.encode(["bytes", "address"], [moduleSignature, this.getAddress()]); // Update userOp with the final signature const updatedUserOp = { ...multiChainUserOps[i].userOp, signature: signatureWithModuleAddress, }; updatedUserOps.push(updatedUserOp); } return updatedUserOps; } catch (error) { common_1.Logger.error("Error in signing multi chain userops", error); throw new Error(JSON.stringify(error)); } } } exports.MultiChainValidationModule = MultiChainValidationModule; //# sourceMappingURL=MultichainValidationModule.js.map