UNPKG

aa-schnorr-multisig-sdk

Version:

Account Abstraction Schnorr Multi-Signatures SDK

97 lines (96 loc) 4.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MultiSigUserOpWithSigners = void 0; const ethers_1 = require("ethers"); const schnorr_helpers_1 = require("../helpers/schnorr-helpers"); const signers_1 = require("../signers"); class MultiSigUserOpWithSigners { constructor(signers, opHash, userOpRequest) { this.publicNonces = {}; this.publicKeys = {}; this.signatures = {}; if (signers.length < 2) throw new Error("At least 2 signers should be provided"); this.signers = signers; this.opHash = opHash; this.userOpRequest = userOpRequest; const _publicKeys = signers.map((signer) => { const _address = signer.getAddress(); // generate and get public nonces if (signer.hasNonces()) throw new Error("Signer already has nonces"); this.publicNonces[_address] = signer.generatePubNonces(); // get public keys const _pk = signer.getPubKey(); this.publicKeys[_address] = _pk; return _pk; }); // get combined public key created from all signers' public keys const _combinedPubKey = signers_1.Schnorrkel.getCombinedPublicKey(_publicKeys); this.combinedPubKey = _combinedPubKey; // create unique tx id const _salt = Buffer.from(ethers_1.ethers.utils.randomBytes(32)); const encodedParams = ethers_1.ethers.utils.defaultAbiCoder.encode(["bytes", "bytes", "bytes"], [_combinedPubKey.buffer, opHash, _salt]); this.id = ethers_1.ethers.utils.keccak256(encodedParams); } getOpHash() { return this.opHash; } signMultiSigHash(signer) { const op = this.opHash; const pk = this._getPublicKeys(); const pn = this._getPublicNonces(); const _signatureOutput = signer.signMultiSigHash(op, pk, pn); this.signatures[signer.getAddress()] = _signatureOutput; return _signatureOutput; } getSummedSigData() { if (!this.combinedPubKey || !this.signatures || this.signers.length < 2) throw new Error("Summed signature input data is missing"); const _signatureOutputs = this._getSignatures(); const _sigs = _signatureOutputs.map((sig) => sig.signature); const _challenges = _signatureOutputs.map((sig) => sig.challenge); // sum all signers signatures const _summed = (0, schnorr_helpers_1.sumSchnorrSigs)(_sigs); // challenge for every signature must be the same - check and if so, assign first one const isEveryChallengeEqual = _challenges.every((e) => { if (e.toHex() === _challenges[0].toHex()) return true; }); if (!isEveryChallengeEqual) throw new Error("Challenges for all signers should be the same"); const e = _challenges[0]; // the multisig px and parity const px = ethers_1.ethers.utils.hexlify(this.combinedPubKey.buffer.subarray(1, 33)); const parity = this.combinedPubKey.buffer[0] - 2 + 27; // wrap the result const abiCoder = new ethers_1.ethers.utils.AbiCoder(); const sigData = abiCoder.encode(["bytes32", "bytes32", "bytes32", "uint8"], [px, e.buffer, _summed.buffer, parity]); return sigData; } getAddressSignature(signerAddress) { return this._getSignatures()[signerAddress]; } getAddressPublicNonces(signerAddress) { return this._getPublicNonces()[signerAddress]; } getAddressPubKeys(signerAddress) { return this._getPublicKeys()[signerAddress]; } _getSignatures() { return Object.entries(this.signatures).map(([, sig]) => { return sig; }); } _getPublicNonces() { return Object.entries(this.publicNonces).map(([, nonce]) => { return nonce; }); } _getPublicKeys() { return Object.entries(this.publicKeys).map(([, pk]) => { return pk; }); } } exports.MultiSigUserOpWithSigners = MultiSigUserOpWithSigners;