@biconomy/modules
Version:
This package provides different validation modules/plugins for ERC4337 compatible modular account
227 lines • 11.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BatchedSessionRouterModule = void 0;
const ethers_1 = require("ethers");
const common_1 = require("@biconomy/common");
const utils_1 = require("ethers/lib/utils");
const Constants_1 = require("./utils/Constants");
const BaseValidationModule_1 = require("./BaseValidationModule");
const SessionKeyManagerModule_1 = require("./SessionKeyManagerModule");
class BatchedSessionRouterModule extends BaseValidationModule_1.BaseValidationModule {
/**
* This constructor is private. Use the static create method to instantiate SessionKeyManagerModule
* @param moduleConfig The configuration for the module
* @returns An instance of SessionKeyManagerModule
*/
constructor(moduleConfig) {
super(moduleConfig);
this.version = "V1_0_0";
this.mockEcdsaSessionKeySig = "0x73c3ac716c487ca34bb858247b5ccf1dc354fbaabdd089af3b2ac8e78ba85a4959a2d76250325bd67c11771c31fccda87c33ceec17cc0de912690521bb95ffcb1b";
/**
* Method to create session data for any module. The session data is used to create a leaf in the merkle tree
* @param leavesData The data of one or more leaves to be used to create session data
* @returns The session data
*/
this.createSessionData = async (leavesData) => {
return this.sessionKeyManagerModule.createSessionData(leavesData);
};
}
/**
* Asynchronously creates and initializes an instance of SessionKeyManagerModule
* @param moduleConfig The configuration for the module
* @returns A Promise that resolves to an instance of SessionKeyManagerModule
*/
static async create(moduleConfig) {
var _a;
const instance = new BatchedSessionRouterModule(moduleConfig);
if (moduleConfig.moduleAddress) {
instance.moduleAddress = moduleConfig.moduleAddress;
}
else if (moduleConfig.version) {
const moduleAddr = Constants_1.BATCHED_SESSION_ROUTER_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_BATCHED_SESSION_ROUTER_MODULE;
// Note: in this case Version remains the default one
}
instance.sessionManagerModuleAddress = (_a = moduleConfig.sessionManagerModuleAddress) !== null && _a !== void 0 ? _a : Constants_1.DEFAULT_SESSION_KEY_MANAGER_MODULE;
if (!moduleConfig.sessionKeyManagerModule) {
// generate sessionModule
const sessionModule = await SessionKeyManagerModule_1.SessionKeyManagerModule.create({
moduleAddress: instance.sessionManagerModuleAddress,
smartAccountAddress: moduleConfig.smartAccountAddress,
nodeClientUrl: moduleConfig.nodeClientUrl,
storageType: moduleConfig.storageType,
});
instance.sessionKeyManagerModule = sessionModule;
}
else {
instance.sessionKeyManagerModule = moduleConfig.sessionKeyManagerModule;
instance.sessionManagerModuleAddress = moduleConfig.sessionKeyManagerModule.getAddress();
}
return instance;
}
/**
* This method is used to sign the user operation using the session signer
* @param userOp The user operation to be signed
* @param sessionParams Information about all the sessions to be used to sign the user operation which has a batch execution
* @returns The signature of the user operation
*/
async signUserOpHash(userOpHash, params) {
var _a;
const sessionParams = params === null || params === void 0 ? void 0 : params.batchSessionParams;
if (!sessionParams || sessionParams.length === 0) {
throw new Error("Session parameters are not provided");
}
const sessionDataTupleArray = [];
// signer must be the same for all the sessions
const sessionSigner = sessionParams[0].sessionSigner;
const signature = await sessionSigner.signMessage((0, utils_1.arrayify)(userOpHash));
for (const sessionParam of sessionParams) {
if (!sessionParam.sessionSigner) {
throw new Error("Session signer is not provided.");
}
const sessionDataTuple = [];
let sessionSignerData;
if (sessionParam.sessionID) {
sessionSignerData = await this.sessionKeyManagerModule.sessionStorageClient.getSessionData({
sessionID: sessionParam.sessionID,
});
}
else if (sessionParam.sessionValidationModule) {
sessionSignerData = await this.sessionKeyManagerModule.sessionStorageClient.getSessionData({
sessionValidationModule: sessionParam.sessionValidationModule,
sessionPublicKey: await sessionSigner.getAddress(),
});
}
else {
throw new Error("sessionID or sessionValidationModule should be provided.");
}
sessionDataTuple.push(sessionSignerData.validUntil);
sessionDataTuple.push(sessionSignerData.validAfter);
sessionDataTuple.push(sessionSignerData.sessionValidationModule);
sessionDataTuple.push(sessionSignerData.sessionKeyData);
const leafDataHex = (0, utils_1.hexConcat)([
(0, utils_1.hexZeroPad)(ethers_1.ethers.utils.hexlify(sessionSignerData.validUntil), 6),
(0, utils_1.hexZeroPad)(ethers_1.ethers.utils.hexlify(sessionSignerData.validAfter), 6),
(0, utils_1.hexZeroPad)(sessionSignerData.sessionValidationModule, 20),
sessionSignerData.sessionKeyData,
]);
const proof = this.sessionKeyManagerModule.merkleTree.getHexProof(ethers_1.ethers.utils.keccak256(leafDataHex));
sessionDataTuple.push(proof);
sessionDataTuple.push((_a = sessionParam.additionalSessionData) !== null && _a !== void 0 ? _a : "0x");
sessionDataTupleArray.push(sessionDataTuple);
}
// Generate the padded signature
const paddedSignature = utils_1.defaultAbiCoder.encode(["address", "tuple(uint48,uint48,address,bytes,bytes32[],bytes)[]", "bytes"], [this.getSessionKeyManagerAddress(), sessionDataTupleArray, signature]);
return paddedSignature;
}
/**
* Update the session data pending state to active
* @param param The search param to find the session data
* @param status The status to be updated
* @returns
*/
async updateSessionStatus(param, status) {
this.sessionKeyManagerModule.sessionStorageClient.updateSessionStatus(param, status);
}
/**
* @remarks This method is used to clear all the pending sessions
* @returns
*/
async clearPendingSessions() {
this.sessionKeyManagerModule.sessionStorageClient.clearPendingSessions();
}
/**
* @returns SessionKeyManagerModule address
*/
getAddress() {
return this.moduleAddress;
}
/**
* @returns SessionKeyManagerModule address
*/
getSessionKeyManagerAddress() {
return this.sessionManagerModuleAddress;
}
/**
* @remarks This is the version of the module contract
*/
async getSigner() {
throw new Error("Method not implemented.");
}
/**
* @remarks This is the dummy signature for the module, used in buildUserOp for bundler estimation
* @returns Dummy signature
*/
async getDummySignature(params) {
var _a;
const sessionParams = params === null || params === void 0 ? void 0 : params.batchSessionParams;
if (!sessionParams || sessionParams.length === 0) {
throw new Error("Session parameters are not provided");
}
const sessionDataTupleArray = [];
// if needed we could do mock signature over userOpHashAndModuleAddress
// signer must be the same for all the sessions
const sessionSigner = sessionParams[0].sessionSigner;
for (const sessionParam of sessionParams) {
if (!sessionParam.sessionSigner) {
throw new Error("Session signer is not provided.");
}
const sessionDataTuple = [];
let sessionSignerData;
if (sessionParam.sessionID) {
sessionSignerData = await this.sessionKeyManagerModule.sessionStorageClient.getSessionData({
sessionID: sessionParam.sessionID,
});
}
else if (sessionParam.sessionValidationModule) {
sessionSignerData = await this.sessionKeyManagerModule.sessionStorageClient.getSessionData({
sessionValidationModule: sessionParam.sessionValidationModule,
sessionPublicKey: await sessionSigner.getAddress(),
});
}
else {
throw new Error("sessionID or sessionValidationModule should be provided.");
}
sessionDataTuple.push(sessionSignerData.validUntil);
sessionDataTuple.push(sessionSignerData.validAfter);
sessionDataTuple.push(sessionSignerData.sessionValidationModule);
sessionDataTuple.push(sessionSignerData.sessionKeyData);
const leafDataHex = (0, utils_1.hexConcat)([
(0, utils_1.hexZeroPad)(ethers_1.ethers.utils.hexlify(sessionSignerData.validUntil), 6),
(0, utils_1.hexZeroPad)(ethers_1.ethers.utils.hexlify(sessionSignerData.validAfter), 6),
(0, utils_1.hexZeroPad)(sessionSignerData.sessionValidationModule, 20),
sessionSignerData.sessionKeyData,
]);
const proof = this.sessionKeyManagerModule.merkleTree.getHexProof(ethers_1.ethers.utils.keccak256(leafDataHex));
sessionDataTuple.push(proof);
sessionDataTuple.push((_a = sessionParam.additionalSessionData) !== null && _a !== void 0 ? _a : "0x");
sessionDataTupleArray.push(sessionDataTuple);
}
// Generate the padded signature
const paddedSignature = utils_1.defaultAbiCoder.encode(["address", "tuple(uint48,uint48,address,bytes,bytes32[],bytes)[]", "bytes"], [this.getSessionKeyManagerAddress(), sessionDataTupleArray, this.mockEcdsaSessionKeySig]);
const dummySig = ethers_1.ethers.utils.defaultAbiCoder.encode(["bytes", "address"], [paddedSignature, this.getAddress()]);
return dummySig;
}
/**
* @remarks Other modules may need additional attributes to build init data
*/
async getInitData() {
throw new Error("Method not implemented.");
}
/**
* @remarks This Module dont have knowledge of signer. So, this method is not implemented
*/
async signMessage(message) {
common_1.Logger.log("message", message);
throw new Error("Method not implemented.");
}
}
exports.BatchedSessionRouterModule = BatchedSessionRouterModule;
//# sourceMappingURL=BatchedSessionRouterModule.js.map