@guru_test/mpc-core-kit
Version:
MPC CoreKit SDK for web3Auth
1,323 lines (1,277 loc) • 92.1 kB
JavaScript
import { TORUS_SAPPHIRE_NETWORK, SIGNER_MAP } from '@toruslabs/constants';
export { SIG_TYPE } from '@toruslabs/constants';
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import { ShareSerializationModule } from '@tkey/share-serialization';
import BN from 'bn.js';
import _objectSpread from '@babel/runtime/helpers/objectSpread2';
import { secp256k1, Point, KeyType, ONE_KEY_DELETE_NONCE, ShareStore, SHARE_DELETED } from '@tkey/common-types';
import { getPubKeyPoint, factorKeyCurve, lagrangeInterpolation, TSSTorusServiceProvider, TKeyTSS } from '@tkey/tss';
export { factorKeyCurve } from '@tkey/tss';
import { keccak256, Torus } from '@toruslabs/torus.js';
import { generatePrivateBN, CoreError } from '@tkey/core';
import { TorusStorageLayer } from '@tkey/storage-layer-torus';
import { UX_MODE, AGGREGATE_VERIFIER, TORUS_METHOD } from '@toruslabs/customauth';
import { Secp256k1Curve, Ed25519Curve } from '@toruslabs/elliptic-wrapper';
import { fetchLocalConfig } from '@toruslabs/fnd-base';
import { keccak256 as keccak256$1 } from '@toruslabs/metadata-helpers';
import { SessionManager } from '@toruslabs/session-manager';
import { setupSockets, getDKLSCoeff, Client } from '@toruslabs/tss-client';
import { sign } from '@toruslabs/tss-frost-client';
import { SafeEventEmitter } from '@web3auth/auth';
import bowser from 'bowser';
import { eddsa, ec } from 'elliptic';
import { safeatob } from '@toruslabs/openlogin-utils';
import loglevel from 'loglevel';
const WEB3AUTH_NETWORK = {
MAINNET: TORUS_SAPPHIRE_NETWORK.SAPPHIRE_MAINNET,
DEVNET: TORUS_SAPPHIRE_NETWORK.SAPPHIRE_DEVNET
};
const USER_PATH = {
NEW: "NewAccount",
EXISTING: "ExistingAccount",
REHYDRATE: "RehydrateAccount",
RECOVER: "RecoverAccount"
};
let FactorKeyTypeShareDescription = /*#__PURE__*/function (FactorKeyTypeShareDescription) {
FactorKeyTypeShareDescription["HashedShare"] = "hashedShare";
FactorKeyTypeShareDescription["SecurityQuestions"] = "tssSecurityQuestions";
FactorKeyTypeShareDescription["DeviceShare"] = "deviceShare";
FactorKeyTypeShareDescription["SeedPhrase"] = "seedPhrase";
FactorKeyTypeShareDescription["PasswordShare"] = "passwordShare";
FactorKeyTypeShareDescription["SocialShare"] = "socialShare";
FactorKeyTypeShareDescription["Other"] = "Other";
return FactorKeyTypeShareDescription;
}({});
const DELIMITERS = {
Delimiter1: "\u001c",
Delimiter2: "\u0015",
Delimiter3: "\u0016",
Delimiter4: "\u0017"
};
const ERRORS = {
TKEY_SHARES_REQUIRED: "required more shares",
INVALID_BACKUP_SHARE: "invalid backup share"
};
const SOCIAL_FACTOR_INDEX = 1;
/**
* Defines the TSS Share Index in a simplified way for better implementation.
**/
let TssShareType = /*#__PURE__*/function (TssShareType) {
TssShareType[TssShareType["DEVICE"] = 2] = "DEVICE";
TssShareType[TssShareType["RECOVERY"] = 3] = "RECOVERY";
return TssShareType;
}({});
const VALID_SHARE_INDICES = [TssShareType.DEVICE, TssShareType.RECOVERY];
const SCALAR_LEN = 32; // Length of secp256k1 scalar in bytes.
const FIELD_ELEMENT_HEX_LEN = 32 * 2; // Length of secp256k1 field element in hex form.
const MAX_FACTORS = 10; // Maximum number of factors that can be added to an account.
const SOCIAL_TKEY_INDEX = 1;
/**
* Fix the prototype chain of the error
*
* Use Object.setPrototypeOf
* Support ES6 environments
*
* Fallback setting __proto__
* Support IE11+, see https://docs.microsoft.com/en-us/scripting/javascript/reference/javascript-version-information
*/
function fixProto(target, prototype) {
const {
setPrototypeOf
} = Object;
if (setPrototypeOf) {
setPrototypeOf(target, prototype);
} else {
// eslint-disable-next-line no-proto, @typescript-eslint/no-explicit-any
target.__proto__ = prototype;
}
}
/**
* Capture and fix the error stack when available
*
* Use Error.captureStackTrace
* Support v8 environments
*/
function fixStack(target, fn = target.constructor) {
const {
captureStackTrace
} = Error;
if (captureStackTrace) {
captureStackTrace(target, fn);
}
}
// copy from https://github.com/microsoft/TypeScript/blob/main/lib/lib.es2022.error.d.ts
// avoid typescript isue https://github.com/adriengibrat/ts-custom-error/issues/81
/**
* Allows to easily extend a base class to create custom applicative errors.
*
* example:
* ```
* class HttpError extends CustomError {
* public constructor(
* public code: number,
* message?: string,
* cause?: Error,
* ) {
* super(message, { cause })
* }
* }
*
* new HttpError(404, 'Not found')
* ```
*/
class CustomError extends Error {
constructor(message, options) {
super(message, options);
// set error name as constructor name, make it not enumerable to keep native Error behavior
// see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target#new.target_in_constructors
// see https://github.com/adriengibrat/ts-custom-error/issues/30
_defineProperty(this, "name", void 0);
Object.defineProperty(this, "name", {
value: new.target.name,
enumerable: false,
configurable: true
});
// fix the extended error prototype chain
// because typescript __extends implementation can't
// see https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
fixProto(this, new.target.prototype);
// try to remove contructor from stack trace
fixStack(this);
}
}
class AbstractCoreKitError extends CustomError {
constructor(code, message) {
// takes care of stack and proto
super(message);
_defineProperty(this, "code", void 0);
_defineProperty(this, "message", void 0);
this.code = code;
this.message = message || "";
// Set name explicitly as minification can mangle class names
Object.defineProperty(this, "name", {
value: "TkeyError"
});
}
toJSON() {
return {
name: this.name,
code: this.code,
message: this.message
};
}
toString() {
return JSON.stringify(this.toJSON());
}
}
/**
* CoreKitError, extension for Error using CustomError
*
* Usage:
* 1. throw CoreKitError.factorKeyNotPresent("Required factor key missing in the operation."); // Use a predefined method to throw a common error
* 2. throw CoreKitError.fromCode(1001); // Throw an error using a code for a common error
* 3. throw new CoreKitError(1102, "'tkey' instance has not been initialized."); // Throw a specific error with a custom message
*
* Guide:
* 1000 - Configuration errors
* 1100 - TSS and key management errors
* 1200 - Factor key and authentication errors
* 1300 - Initialization and session management
*/
class CoreKitError extends AbstractCoreKitError {
constructor(code, message) {
super(code, message);
Object.defineProperty(this, "name", {
value: "CoreKitError"
});
}
static fromCode(code, extraMessage = "") {
return new CoreKitError(code, `${CoreKitError.messages[code]} ${extraMessage}`);
}
static default(extraMessage = "") {
return new CoreKitError(1000, `${CoreKitError.messages[1000]} ${extraMessage}`);
}
// Configuration errors
static chainConfigInvalid(extraMessage = "") {
return CoreKitError.fromCode(1001, extraMessage);
}
static clientIdInvalid(extraMessage = "") {
return CoreKitError.fromCode(1002, extraMessage);
}
static storageTypeUnsupported(extraMessage = "") {
return CoreKitError.fromCode(1003, extraMessage);
}
static oauthLoginUnsupported(extraMessage = "") {
return CoreKitError.fromCode(1004, extraMessage);
}
static noValidStorageOptionFound(extraMessage = "") {
return CoreKitError.fromCode(1005, extraMessage);
}
static noDataFoundInStorage(extraMessage = "") {
return CoreKitError.fromCode(1006, extraMessage);
}
static invalidConfig(extraMessage = "") {
return CoreKitError.fromCode(1007, extraMessage);
}
static invalidKeyType(extraMessage = "") {
return CoreKitError.fromCode(1008, extraMessage);
}
static invalidSigType(extraMessage = "") {
return CoreKitError.fromCode(1009, extraMessage);
}
// TSS and key management errors
static tssLibRequired(extraMessage = "") {
return CoreKitError.fromCode(1101, extraMessage);
}
static tkeyInstanceUninitialized(extraMessage = "") {
return CoreKitError.fromCode(1102, extraMessage);
}
static duplicateTssIndex(extraMessage = "") {
return CoreKitError.fromCode(1103, extraMessage);
}
static nodeDetailsRetrievalFailed(extraMessage = "") {
return CoreKitError.fromCode(1104, extraMessage);
}
static prefetchValueExceeded(extraMessage = "") {
return CoreKitError.fromCode(1105, extraMessage);
}
static invalidTorusLoginResponse(extraMessage = "") {
return CoreKitError.fromCode(1106, extraMessage);
}
static invalidTorusAggregateLoginResponse(extraMessage = "") {
return CoreKitError.fromCode(1107, extraMessage);
}
static unsupportedRedirectMethod(extraMessage = "") {
return CoreKitError.fromCode(1108, extraMessage);
}
static postBoxKeyMissing(extraMessage = "") {
return CoreKitError.fromCode(1109, extraMessage);
}
static tssShareTypeIndexMissing(extraMessage = "") {
return CoreKitError.fromCode(1110, extraMessage);
}
static tssPublicKeyOrEndpointsMissing(extraMessage = "") {
return CoreKitError.fromCode(1111, extraMessage);
}
static activeSessionNotFound(extraMessage = "") {
return CoreKitError.fromCode(1112, extraMessage);
}
static tssNoncesMissing(extraMessage = "") {
return CoreKitError.fromCode(1113, extraMessage);
}
static tssKeyImportNotAllowed(extraMessage = "") {
return CoreKitError.fromCode(1114, extraMessage);
}
// Factor key and authentication errors
static factorKeyNotPresent(extraMessage = "") {
return CoreKitError.fromCode(1201, extraMessage);
}
static factorKeyAlreadyExists(extraMessage = "") {
return CoreKitError.fromCode(1202, extraMessage);
}
static mfaAlreadyEnabled(extraMessage = "") {
return CoreKitError.fromCode(1203, extraMessage);
}
static cannotDeleteLastFactor(extraMessage = "") {
return CoreKitError.fromCode(1204, extraMessage);
}
static factorInUseCannotBeDeleted(extraMessage = "") {
return CoreKitError.fromCode(1205, extraMessage);
}
static userNotLoggedIn(extraMessage = "") {
return CoreKitError.fromCode(1206, extraMessage);
}
static providedFactorKeyInvalid(extraMessage = "") {
return CoreKitError.fromCode(1207, extraMessage);
}
static factorEncsMissing(extraMessage = "") {
return CoreKitError.fromCode(1208, extraMessage);
}
static noMetadataFound(extraMessage = "") {
return CoreKitError.fromCode(1209, extraMessage);
}
static newShareIndexInvalid(extraMessage = "") {
return CoreKitError.fromCode(1210, extraMessage);
}
static maximumFactorsReached(extraMessage = "") {
return CoreKitError.fromCode(1211, extraMessage);
}
static noMetadataShareFound(extraMessage = "") {
return CoreKitError.fromCode(1212, extraMessage);
}
static signaturesNotPresent(extraMessage = "") {
return CoreKitError.fromCode(1213, extraMessage);
}
static factorPubsMissing(extraMessage = "") {
return CoreKitError.fromCode(1214, extraMessage);
}
// Initialization and session management
static commitChangesBeforeMFA(extraMessage = "") {
return CoreKitError.fromCode(1301, extraMessage);
}
static mpcCoreKitNotInitialized(extraMessage = "") {
return CoreKitError.fromCode(1302, extraMessage);
}
}
_defineProperty(CoreKitError, "messages", {
// Configuration errors
1001: "You must specify a valid eip155 chain configuration in the options.",
1002: "You must specify a web3auth clientId.",
1003: "Unsupported storage type in this UX mode.",
1004: "OAuth login is NOT supported in this UX mode.",
1005: "No valid storage option found.",
1006: "No data found in storage.",
1007: "Invalid config.",
1008: "Invalid key type.",
1009: "Invalid signature type.",
// TSS and key management errors
1101: "'tssLib' is required when running in this UX mode.",
1102: "'tkey' instance has not been initialized.",
1103: "Duplicate TSS index found. Ensure that each TSS index is unique.",
1104: "Failed to retrieve node details. Please check your network connection and try again.",
1105: "The prefetch TSS public keys exceeds the maximum allowed limit of 3.",
1106: "Invalid 'TorusLoginResponse' data provided.",
1107: "Invalid 'TorusAggregateLoginResponse' data provided.",
1108: "Unsupported method type encountered in redirect result.",
1109: "OAuthKey not present in state.",
1110: "TSS Share Type (Index) not present in state when getting current factor key.",
1111: "'tssPubKey' or 'torusNodeTSSEndpoints' are missing.",
1112: "No active session found.",
1113: "tssNonces not present in metadata when getting tss nonce.",
1114: "A TSS key cannot be imported for an existing user who already has a key configured.",
// Factor key and authentication errors
1201: "factorKey not present in state when required.",
1202: "A factor with the same key already exists.",
1203: "MFA is already enabled.",
1204: "Cannot delete the last remaining factor as at least one factor is required.",
1205: "The factor currently in use cannot be deleted.",
1206: "User is not logged in.",
1207: "Provided factor key is invalid.",
1208: "'factorEncs' mpt [resemt].",
1209: "No metadata found for the provided factor key. Consider resetting your account if this error persists.",
1210: "The new share index is not valid. It must be one of the valid share indices.",
1211: "The maximum number of allowable factors (10) has been reached.",
1212: "No metadata share found in the current polynomial.",
1213: "No signatures found.",
1214: "Factor public keys not present",
// Initialization and session management
1301: "The 'CommitChanges' method must be called before enabling MFA.",
1302: "The MPC Core Kit is not initialized. Please ensure you call the 'init()' method to initialize the kit properly before attempting any operations."
});
class MemoryStorage {
constructor() {
_defineProperty(this, "_store", {});
}
getItem(key) {
return this._store[key] || null;
}
setItem(key, value) {
this._store[key] = value;
}
removeItem(key) {
delete this._store[key];
}
clear() {
this._store = {};
}
}
class AsyncStorage {
constructor(storeKey, storage) {
_defineProperty(this, "storage", void 0);
_defineProperty(this, "_storeKey", void 0);
this.storage = storage;
this._storeKey = storeKey;
}
async toJSON() {
const result = await this.storage.getItem(this._storeKey);
if (!result) {
throw CoreKitError.noDataFoundInStorage(`No data found in storage under key '${this._storeKey}'.`);
}
return result;
}
async resetStore() {
const currStore = await this.getStore();
await this.storage.setItem(this._storeKey, JSON.stringify({}));
return currStore;
}
async getStore() {
return JSON.parse((await this.storage.getItem(this._storeKey)) || "{}");
}
async get(key) {
const store = JSON.parse((await this.storage.getItem(this._storeKey)) || "{}");
return store[key];
}
async set(key, value) {
const store = JSON.parse((await this.storage.getItem(this._storeKey)) || "{}");
store[key] = value;
await this.storage.setItem(this._storeKey, JSON.stringify(store));
}
async remove(key) {
const store = JSON.parse((await this.storage.getItem(this._storeKey)) || "{}");
delete store[key];
await this.storage.setItem(this._storeKey, JSON.stringify(store));
}
}
/**
* Converts a mnemonic to a BN.
* @param shareMnemonic - The mnemonic to convert.
* @returns A BN respective to your mnemonic
*/
function mnemonicToKey(shareMnemonic) {
const factorKey = ShareSerializationModule.deserializeMnemonic(shareMnemonic);
return factorKey.toString("hex");
}
/**
* Converts a BN to a mnemonic.
* @param shareBN - The BN to convert.
* @returns A mnemonic respective to your BN
*/
function keyToMnemonic(shareHex) {
const shareBN = new BN(shareHex, "hex");
const mnemonic = ShareSerializationModule.serializeMnemonic(shareBN);
return mnemonic;
}
class TssSecurityQuestionStore {
constructor(shareIndex, factorPublicKey, question) {
_defineProperty(this, "shareIndex", void 0);
_defineProperty(this, "factorPublicKey", void 0);
_defineProperty(this, "question", void 0);
this.shareIndex = shareIndex;
this.factorPublicKey = factorPublicKey;
this.question = question;
}
static fromJSON(json) {
const {
shareIndex,
factorPublicKey,
question
} = json;
return new TssSecurityQuestionStore(shareIndex, factorPublicKey, question);
}
toJSON() {
return {
shareIndex: this.shareIndex,
factorPublicKey: this.factorPublicKey,
question: this.question
};
}
}
class TssSecurityQuestion {
constructor() {
_defineProperty(this, "storeDomainName", "tssSecurityQuestion");
}
async setSecurityQuestion(params) {
const {
mpcCoreKit,
question,
answer,
description
} = params;
let {
shareType
} = params;
if (!mpcCoreKit.tKey) {
throw new Error("Tkey not initialized, call init first.");
}
if (!question || !answer) {
throw new Error("question and answer are required");
}
const domainKey = `${this.storeDomainName}:${params.mpcCoreKit.tKey.tssTag}`;
// default using recovery index
if (!shareType) {
shareType = TssShareType.RECOVERY;
} else if (!VALID_SHARE_INDICES.includes(shareType)) {
throw new Error(`invalid share type: must be one of ${VALID_SHARE_INDICES}`);
}
// Check for existing security question
const tkey = mpcCoreKit.tKey;
const storeDomain = tkey.metadata.getGeneralStoreDomain(domainKey);
if (storeDomain && storeDomain.question) {
throw new Error("Security question already exists");
}
// const pubKey = Point.fromTkeyPoint(mpcCoreKit.tKey.getTSSPub()).toBufferSEC1(true).toString("hex");
const pubKey = tkey.getKeyDetails().pubKey.toSEC1(secp256k1, true).toString("hex") + tkey.tssTag;
let hash = keccak256(Buffer.from(answer + pubKey, "utf8"));
hash = hash.startsWith("0x") ? hash.slice(2) : hash;
const factorKeyBN = new BN(hash, "hex");
const descriptionFinal = _objectSpread({
question
}, description);
await mpcCoreKit.createFactor({
factorKey: factorKeyBN,
shareType,
shareDescription: FactorKeyTypeShareDescription.SecurityQuestions,
additionalMetadata: descriptionFinal
});
// set store domain
const tkeyPt = getPubKeyPoint(factorKeyBN, factorKeyCurve);
const factorPub = tkeyPt.toSEC1(factorKeyCurve, true).toString("hex");
const storeData = new TssSecurityQuestionStore(shareType.toString(), factorPub, question);
tkey.metadata.setGeneralStoreDomain(domainKey, storeData.toJSON());
// check for auto commit
if (!tkey.manualSync) await tkey._syncShareMetadata();
return factorKeyBN.toString("hex").padStart(64, "0");
}
async changeSecurityQuestion(params) {
const {
mpcCoreKit,
newQuestion,
newAnswer,
answer
} = params;
if (!newQuestion || !newAnswer || !answer) {
throw new Error("question and answer are required");
}
// Check for existing security question
const tkey = mpcCoreKit.tKey;
// const pubKey = Point.fromTkeyPoint(mpcCoreKit.tKey.getTSSPub()).toBufferSEC1(true).toString("hex");
const pubKey = tkey.getKeyDetails().pubKey.toSEC1(secp256k1, true).toString("hex") + tkey.tssTag;
const domainKey = `${this.storeDomainName}:${params.mpcCoreKit.tKey.tssTag}`;
const storeDomain = tkey.metadata.getGeneralStoreDomain(domainKey);
if (!storeDomain || !storeDomain.question) {
throw new Error("Security question does not exists");
}
const store = TssSecurityQuestionStore.fromJSON(storeDomain);
const preHash = answer + pubKey;
let hash = keccak256(Buffer.from(preHash, "utf8"));
hash = hash.startsWith("0x") ? hash.slice(2) : hash;
const factorKeyBN = new BN(hash, "hex");
const factorKeyPt = getPubKeyPoint(factorKeyBN, factorKeyCurve);
if (factorKeyPt.toSEC1(factorKeyCurve, true).toString("hex") !== store.factorPublicKey) {
throw new Error("Invalid answer");
}
// create new factor key
const prenewHash = newAnswer + pubKey;
let newHash = keccak256(Buffer.from(prenewHash, "utf8"));
newHash = newHash.startsWith("0x") ? newHash.slice(2) : newHash;
const newAnswerBN = new BN(newHash, "hex");
const newFactorPt = Point.fromScalar(newAnswerBN, factorKeyCurve);
await mpcCoreKit.createFactor({
factorKey: newAnswerBN,
shareType: parseInt(store.shareIndex),
shareDescription: FactorKeyTypeShareDescription.SecurityQuestions
});
// update mpcCoreKit state to use new factor key during change password if mpc factor key is security question factor
if (mpcCoreKit.state.factorKey.eq(factorKeyBN)) {
await mpcCoreKit.inputFactorKey(newAnswerBN);
}
// delete after create factor to prevent last key issue
// delete old factor key and device share
await mpcCoreKit.deleteFactor(factorKeyPt, factorKeyBN);
store.factorPublicKey = newFactorPt.toSEC1(factorKeyCurve, true).toString("hex");
store.question = newQuestion;
tkey.metadata.setGeneralStoreDomain(domainKey, store.toJSON());
// check for auto commit
if (!tkey.manualSync) await tkey._syncShareMetadata();
}
// Should we check with answer before deleting?
async deleteSecurityQuestion(mpcCoreKit, deleteFactorKey = true) {
if (!mpcCoreKit.tKey) {
throw new Error("Tkey not initialized, call init first.");
}
const domainKey = `${this.storeDomainName}:${mpcCoreKit.tKey.tssTag}`;
const tkey = mpcCoreKit.tKey;
if (deleteFactorKey) {
const storeDomain = tkey.metadata.getGeneralStoreDomain(domainKey);
if (!storeDomain || !storeDomain.question) {
throw new Error("Security question does not exists");
}
const store = TssSecurityQuestionStore.fromJSON(storeDomain);
if (store.factorPublicKey) {
await mpcCoreKit.deleteFactor(Point.fromSEC1(factorKeyCurve, store.factorPublicKey));
}
}
tkey.metadata.deleteGeneralStoreDomain(domainKey);
// check for auto commit
if (!tkey.manualSync) await tkey._syncShareMetadata();
}
async recoverFactor(mpcCoreKit, answer) {
if (!mpcCoreKit.tKey) {
throw new Error("Tkey not initialized, call init first.");
}
if (!answer) {
throw new Error("question and answer are required");
}
const tkey = mpcCoreKit.tKey;
const domainKey = `${this.storeDomainName}:${mpcCoreKit.tKey.tssTag}`;
const storeDomain = tkey.metadata.getGeneralStoreDomain(domainKey);
if (!storeDomain || !storeDomain.question) {
throw new Error("Security question does not exists");
}
const store = TssSecurityQuestionStore.fromJSON(storeDomain);
// const pubKey = Point.fromTkeyPoint(mpcCoreKit.tKey.getTSSPub()).toBufferSEC1(true).toString("hex");
const pubKey = tkey.getKeyDetails().pubKey.toSEC1(secp256k1, true).toString("hex") + tkey.tssTag;
let hash = keccak256(Buffer.from(answer + pubKey, "utf8"));
hash = hash.startsWith("0x") ? hash.slice(2) : hash;
const factorKeyBN = new BN(hash, "hex");
const factorKeyPt = Point.fromScalar(factorKeyBN, factorKeyCurve);
if (factorKeyPt.toSEC1(factorKeyCurve, true).toString("hex") !== store.factorPublicKey) {
throw new Error("Invalid answer");
}
return hash;
}
getQuestion(mpcCoreKit) {
if (!mpcCoreKit.tKey) {
throw new Error("Tkey not initialized, call init first.");
}
const tkey = mpcCoreKit.tKey;
const domainKey = `${this.storeDomainName}:${mpcCoreKit.tKey.tssTag}`;
const storeDomain = tkey.metadata.getGeneralStoreDomain(domainKey);
if (!storeDomain || !storeDomain.question) {
throw new Error("Security question does not exists");
}
const store = TssSecurityQuestionStore.fromJSON(storeDomain);
return store.question;
}
}
// TODO: move the types to a base class for both dkls and frost in future
let COREKIT_STATUS = /*#__PURE__*/function (COREKIT_STATUS) {
COREKIT_STATUS["NOT_INITIALIZED"] = "NOT_INITIALIZED";
COREKIT_STATUS["INITIALIZED"] = "INITIALIZED";
COREKIT_STATUS["REQUIRED_SHARE"] = "REQUIRED_SHARE";
COREKIT_STATUS["LOGGED_IN"] = "LOGGED_IN";
return COREKIT_STATUS;
}({});
class DefaultSessionSigGeneratorPlugin {
constructor(mpcCorekitContext) {
this.mpcCorekitContext = mpcCorekitContext;
_defineProperty(this, "context", void 0);
this.context = mpcCorekitContext;
}
async getSessionSigs() {
return this.context.state.signatures || [];
}
}
const ed25519 = () => {
return new eddsa("ed25519");
};
/**
* Secure PRNG. Uses `crypto.getRandomValues`, which defers to OS.
*/
function randomBytes(bytesLength = 32) {
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
const crypto = typeof globalThis === "object" && "crypto" in globalThis ? globalThis.crypto : undefined;
if (crypto && typeof crypto.getRandomValues === "function") {
return crypto.getRandomValues(new Uint8Array(bytesLength));
}
throw new Error("crypto.getRandomValues must be defined");
}
function generateEd25519Seed() {
return Buffer.from(randomBytes(32));
}
const generateFactorKey = () => {
const keyPair = factorKeyCurve.genKeyPair();
const pub = Point.fromElliptic(keyPair.getPublic());
return {
private: keyPair.getPrivate(),
pub
};
};
const generateTSSEndpoints = (tssNodeEndpoints, parties, clientIndex, nodeIndexes) => {
const endpoints = [];
const tssWSEndpoints = [];
const partyIndexes = [];
const nodeIndexesReturned = [];
for (let i = 0; i < parties; i++) {
partyIndexes.push(i);
if (i === clientIndex) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
endpoints.push(null);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
tssWSEndpoints.push(null);
} else {
const targetNodeIndex = nodeIndexes[i] - 1;
endpoints.push(tssNodeEndpoints[targetNodeIndex]);
tssWSEndpoints.push(new URL(tssNodeEndpoints[targetNodeIndex]).origin);
nodeIndexesReturned.push(nodeIndexes[i]);
}
}
return {
endpoints,
tssWSEndpoints,
partyIndexes,
nodeIndexesReturned
};
};
async function storageAvailable(storage) {
try {
const x = "__storage_test__";
const rand = Math.random().toString();
await storage.setItem(x, rand);
const value = await storage.getItem(rand);
if (value !== rand) {
throw new Error("Value mismatch");
}
return true;
} catch (error) {
return false;
}
}
// TODO think which conversion functions to keep and how to export them.
/**
* Parses a JWT Token, without verifying the signature.
* @param token - JWT Token
* @returns Extracted JSON payload from the token
*/
function parseToken(token) {
const payload = token.split(".")[1];
return JSON.parse(safeatob(payload));
}
const getHashedPrivateKey = (postboxKey, clientId) => {
const uid = `${postboxKey}_${clientId}`;
let hashUid = keccak256(Buffer.from(uid, "utf8"));
hashUid = hashUid.replace("0x", "");
return new BN(hashUid, "hex");
};
/**
* Converts an elliptic curve scalar represented by a BN to a byte buffer in SEC1
* format (i.e., padded to maximum length).
* @param s - The scalar of type BN.
* @returns The SEC1 encoded representation of the scalar.
*/
function scalarBNToBufferSEC1(s) {
return s.toArrayLike(Buffer, "be", SCALAR_LEN);
}
function sampleEndpoints(endpoints, n) {
if (n > endpoints.length) {
throw new Error("Invalid number of endpoints");
}
const shuffledEndpoints = endpoints.slice().sort(() => Math.random() - 0.5);
return shuffledEndpoints.slice(0, n).sort((a, b) => a.index - b.index);
}
function fraction(curve, nom, denom) {
return nom.mul(denom.invm(curve.n)).umod(curve.n);
}
function lagrangeCoefficient(curve, xCoords, targetCoeff, targetX) {
return xCoords.filter((_, i) => i !== targetCoeff).reduce((prev, cur) => {
const frac = fraction(curve, targetX.sub(cur), xCoords[targetCoeff].sub(cur));
return prev.mul(frac).umod(curve.n);
}, new BN(1));
}
function lagrangeCoefficients(curve, xCoords, targetX) {
const xCoordsBN = xCoords.map(i => new BN(i));
const targetXBN = new BN(targetX);
return xCoordsBN.map((_value, i) => lagrangeCoefficient(curve, xCoordsBN, i, targetXBN));
}
const SERVER_XCOORD_L1 = 1;
const CLIENT_XCOORD_L1 = 2;
/**
* Derive share coefficients for client and servers.
*
* @param curve - The curve to be used.
* @param serverXCoords - The source and target x-coordinates of the selected
* servers.
* @param targetClientXCoord - The target x-coordinate of the client.
* @param sourceClientXCoord - The source x-coordinate of the client in the L1
* hierarchy.
* @returns - The share coefficients for the client and the servers.
*/
function deriveShareCoefficients(ec, serverXCoords, targetClientXCoord, sourceClientXCoord = CLIENT_XCOORD_L1) {
const l1Coefficients = lagrangeCoefficients(ec, [SERVER_XCOORD_L1, sourceClientXCoord], 0);
const l2Coefficients = lagrangeCoefficients(ec, serverXCoords, 0);
if (serverXCoords.includes(targetClientXCoord)) {
throw new Error(`Invalid server x-coordinates: overlapping with client x-coordinate: ${serverXCoords} ${targetClientXCoord}`);
}
const targetCoefficients = lagrangeCoefficients(ec, [targetClientXCoord, ...serverXCoords], 0);
// Derive server coefficients.
const serverCoefficients = l2Coefficients.map((coeff, i) => fraction(ec, l1Coefficients[0].mul(coeff), targetCoefficients[i + 1]));
// Derive client coefficient.
const clientCoefficient = fraction(ec, l1Coefficients[1], targetCoefficients[0]);
return {
serverCoefficients,
clientCoefficient
};
}
function generateSessionNonce() {
return keccak256(Buffer.from(generatePrivateBN().toString("hex") + Date.now(), "utf8"));
}
function getSessionId(verifier, verifierId, tssTag, tssNonce, sessionNonce) {
return `${verifier}${DELIMITERS.Delimiter1}${verifierId}${DELIMITERS.Delimiter2}${tssTag}${DELIMITERS.Delimiter3}${tssNonce}${DELIMITERS.Delimiter4}${sessionNonce}`;
}
function sigToRSV(sig) {
if (sig.length !== 65) {
throw new Error(`Invalid signature length: expected 65, got ${sig.length}`);
}
return {
r: sig.subarray(0, 32),
s: sig.subarray(32, 64),
v: sig[64]
};
}
function makeEthereumSigner(kit) {
if (kit.keyType !== KeyType.secp256k1) {
throw new Error(`Invalid key type: expected secp256k1, got ${kit.keyType}`);
}
return {
sign: async msgHash => {
const sig = await kit.sign(msgHash, {
hashed: true
});
return sigToRSV(sig);
},
getPublic: async () => {
const pk = Point.fromSEC1(secp256k1, kit.getPubKey().toString("hex"));
return pk.toSEC1(secp256k1).subarray(1);
}
};
}
const log = loglevel.getLogger("mpc-core-kit");
log.disableAll();
class Web3AuthMPCCoreKit {
constructor(options) {
var _window;
_defineProperty(this, "state", {
accountIndex: 0
});
_defineProperty(this, "torusSp", null);
_defineProperty(this, "stateEmitter", void 0);
_defineProperty(this, "options", void 0);
_defineProperty(this, "storageLayer", null);
_defineProperty(this, "tkey", null);
_defineProperty(this, "sessionManager", void 0);
_defineProperty(this, "currentStorage", void 0);
_defineProperty(this, "_storageBaseKey", "corekit_store");
_defineProperty(this, "enableLogging", false);
_defineProperty(this, "ready", false);
_defineProperty(this, "_tssLib", void 0);
_defineProperty(this, "wasmLib", void 0);
_defineProperty(this, "_keyType", void 0);
_defineProperty(this, "_sigType", void 0);
_defineProperty(this, "atomicCallStackCounter", 0);
_defineProperty(this, "sessionSigGenerator", void 0);
_defineProperty(this, "getTssFactorPub", () => {
this.checkReady();
if (!this.state.factorKey) {
throw CoreKitError.factorKeyNotPresent("factorKey not present in state when getting tss factor public key.");
}
const factorPubsList = this.tKey.metadata.factorPubs[this.tKey.tssTag];
return factorPubsList.map(factorPub => factorPub.toSEC1(factorKeyCurve, true).toString("hex"));
});
if (!options.web3AuthClientId) {
throw CoreKitError.clientIdInvalid();
}
this._tssLib = options.tssLib;
this._keyType = options.tssLib.keyType;
this._sigType = options.tssLib.sigType;
const isNodejsOrRN = this.isNodejsOrRN(options.uxMode);
if (options.enableLogging) {
log.enableAll();
this.enableLogging = true;
} else log.setLevel("error");
if (typeof options.manualSync !== "boolean") options.manualSync = false;
if (!options.web3AuthNetwork) options.web3AuthNetwork = WEB3AUTH_NETWORK.MAINNET;
// if sessionTime is not provided, it is defaulted to 86400
if (!options.sessionTime) options.sessionTime = 86400;
if (!options.serverTimeOffset) options.serverTimeOffset = 0;
if (!options.uxMode) options.uxMode = UX_MODE.REDIRECT;
if (!options.redirectPathName) options.redirectPathName = "redirect";
if (!options.baseUrl) options.baseUrl = isNodejsOrRN ? "https://localhost" : `${(_window = window) === null || _window === void 0 ? void 0 : _window.location.origin}/serviceworker`;
if (!options.disableHashedFactorKey) options.disableHashedFactorKey = false;
if (!options.hashedFactorNonce) options.hashedFactorNonce = options.web3AuthClientId;
if (options.disableSessionManager === undefined) options.disableSessionManager = false;
this.sessionSigGenerator = new DefaultSessionSigGeneratorPlugin(this);
this.options = options;
this.currentStorage = new AsyncStorage(this._storageBaseKey, options.storage);
this.stateEmitter = new SafeEventEmitter();
if (!options.disableSessionManager) {
this.sessionManager = new SessionManager({
sessionTime: options.sessionTime
});
}
Torus.setSessionTime(this.options.sessionTime);
}
get tKey() {
if (this.tkey === null) {
throw CoreKitError.tkeyInstanceUninitialized();
}
return this.tkey;
}
get keyType() {
return this._keyType;
}
get sigType() {
return this._sigType;
}
get config() {
return this.options;
}
get _storageKey() {
return this._storageBaseKey;
}
get status() {
try {
// metadata will be present if tkey is initialized (1 share)
// if 2 shares are present, then privKey will be present after metadatakey(tkey) reconstruction
const {
tkey
} = this;
if (!tkey) return COREKIT_STATUS.NOT_INITIALIZED;
if (!tkey.metadata) return COREKIT_STATUS.INITIALIZED;
if (!tkey.secp256k1Key || !this.state.factorKey) return COREKIT_STATUS.REQUIRED_SHARE;
return COREKIT_STATUS.LOGGED_IN;
} catch (e) {}
return COREKIT_STATUS.NOT_INITIALIZED;
}
get sessionId() {
var _this$sessionManager;
return (_this$sessionManager = this.sessionManager) === null || _this$sessionManager === void 0 ? void 0 : _this$sessionManager.sessionId;
}
get supportsAccountIndex() {
return this._sigType !== "ed25519";
}
get verifier() {
var _this$state$userInfo, _this$state;
if ((_this$state$userInfo = this.state.userInfo) !== null && _this$state$userInfo !== void 0 && _this$state$userInfo.aggregateVerifier) {
return this.state.userInfo.aggregateVerifier;
}
return (_this$state = this.state) !== null && _this$state !== void 0 && (_this$state = _this$state.userInfo) !== null && _this$state !== void 0 && _this$state.verifier ? this.state.userInfo.verifier : "";
}
get verifierId() {
var _this$state2;
return (_this$state2 = this.state) !== null && _this$state2 !== void 0 && (_this$state2 = _this$state2.userInfo) !== null && _this$state2 !== void 0 && _this$state2.verifierId ? this.state.userInfo.verifierId : "";
}
get isRedirectMode() {
return this.options.uxMode === UX_MODE.REDIRECT;
}
get useClientGeneratedTSSKey() {
return this._sigType === "ed25519" && this.options.useClientGeneratedTSSKey === undefined ? true : !!this.options.useClientGeneratedTSSKey;
}
setCustomSessionSigGenerator(sessionSigGenerator) {
this.sessionSigGenerator = sessionSigGenerator;
}
async getSessionSignatures() {
return this.sessionSigGenerator.getSessionSigs();
}
// RecoverTssKey only valid for user that enable MFA where user has 2 type shares :
// TssShareType.DEVICE and TssShareType.RECOVERY
// if the factors key provided is the same type recovery will not works
async _UNSAFE_recoverTssKey(factorKey) {
this.checkReady();
const factorKeyBN = new BN(factorKey[0], "hex");
const shareStore0 = await this.getFactorKeyMetadata(factorKeyBN);
await this.tKey.initialize({
withShare: shareStore0
});
const tssShares = [];
const tssIndexes = [];
const tssIndexesBN = [];
for (let i = 0; i < factorKey.length; i++) {
const factorKeyBNInput = new BN(factorKey[i], "hex");
const {
tssIndex,
tssShare
} = await this.tKey.getTSSShare(factorKeyBNInput);
if (tssIndexes.includes(tssIndex)) {
// reset instance before throw error
await this.init();
throw CoreKitError.duplicateTssIndex();
}
tssIndexes.push(tssIndex);
tssIndexesBN.push(new BN(tssIndex));
tssShares.push(tssShare);
}
const finalKey = lagrangeInterpolation(this.tkey.tssCurve, tssShares, tssIndexesBN);
// reset instance after recovery completed
await this.init();
return finalKey.toString("hex", 64);
}
async init(params = {
handleRedirectResult: true
}) {
var _window2, _window3;
this.resetState();
if (params.rehydrate === undefined) params.rehydrate = true;
const nodeDetails = fetchLocalConfig(this.options.web3AuthNetwork, this.keyType);
if (this._sigType === "ed25519" && this.options.useDKG) {
throw CoreKitError.invalidConfig("DKG is not supported for ed25519 signature type");
}
this.torusSp = new TSSTorusServiceProvider({
customAuthArgs: {
web3AuthClientId: this.options.web3AuthClientId,
baseUrl: this.options.baseUrl,
uxMode: this.isNodejsOrRN(this.options.uxMode) ? UX_MODE.REDIRECT : this.options.uxMode,
network: this.options.web3AuthNetwork,
redirectPathName: this.options.redirectPathName,
locationReplaceOnRedirect: true,
serverTimeOffset: this.options.serverTimeOffset,
keyType: this.keyType,
useDkg: this.options.useDKG
}
});
this.storageLayer = new TorusStorageLayer({
hostUrl: `${new URL(nodeDetails.torusNodeEndpoints[0]).origin}/metadata`,
enableLogging: this.enableLogging
});
const shareSerializationModule = new ShareSerializationModule();
this.tkey = new TKeyTSS({
enableLogging: this.enableLogging,
serviceProvider: this.torusSp,
storageLayer: this.storageLayer,
manualSync: this.options.manualSync,
modules: {
shareSerialization: shareSerializationModule
},
tssKeyType: this.keyType
});
if (this.isRedirectMode) {
await this.torusSp.init({
skipSw: true,
skipPrefetch: true
});
} else if (this.options.uxMode === UX_MODE.POPUP) {
await this.torusSp.init({});
}
this.ready = true;
// try handle redirect flow if enabled and return(redirect) from oauth login
if (params.handleRedirectResult && this.options.uxMode === UX_MODE.REDIRECT && ((_window2 = window) !== null && _window2 !== void 0 && _window2.location.hash.includes("#state") || (_window3 = window) !== null && _window3 !== void 0 && _window3.location.hash.includes("#access_token"))) {
// on failed redirect, instance is reseted.
// skip check feature gating on redirection as it was check before login
await this.handleRedirectResult();
// return early on successful redirect, the rest of the code will not be executed
return;
} else if (params.rehydrate && this.sessionManager) {
// if not redirect flow try to rehydrate session if available
const sessionId = await this.currentStorage.get("sessionId");
if (sessionId) {
this.sessionManager.sessionId = sessionId;
// swallowed, should not throw on rehydrate timed out session
const sessionResult = await this.sessionManager.authorizeSession().catch(async err => {
log.error("rehydrate session error", err);
});
// try rehydrate session
if (sessionResult) {
await this.rehydrateSession(sessionResult);
// return early on success rehydration
return;
}
}
}
// feature gating if not redirect flow or session rehydration
await this.featureRequest();
}
async loginWithOAuth(params) {
this.checkReady();
if (this.isNodejsOrRN(this.options.uxMode)) {
throw CoreKitError.oauthLoginUnsupported(`Oauth login is NOT supported in ${this.options.uxMode} mode.`);
}
const {
importTssKey,
registerExistingSFAKey
} = params;
const tkeyServiceProvider = this.torusSp;
if (registerExistingSFAKey && importTssKey) {
throw CoreKitError.invalidConfig("Cannot import TSS key and register SFA key at the same time.");
}
if (this.isRedirectMode && (importTssKey || registerExistingSFAKey)) {
throw CoreKitError.invalidConfig("key import is not supported in redirect mode");
}
try {
// oAuth login.
const verifierParams = params;
const aggregateParams = params;
let loginResponse;
let userInfo;
if (verifierParams.subVerifierDetails) {
// single verifier login.
loginResponse = await tkeyServiceProvider.triggerLogin(params.subVerifierDetails);
userInfo = loginResponse.userInfo;
if (this.isRedirectMode) return;
} else if (aggregateParams.subVerifierDetailsArray) {
loginResponse = await tkeyServiceProvider.triggerAggregateLogin({
aggregateVerifierType: aggregateParams.aggregateVerifierType || AGGREGATE_VERIFIER.SINGLE_VERIFIER_ID,
verifierIdentifier: aggregateParams.aggregateVerifierIdentifier,
subVerifierDetailsArray: aggregateParams.subVerifierDetailsArray
});
userInfo = loginResponse.userInfo[0];
if (this.isRedirectMode) return;
}
if (loginResponse && registerExistingSFAKey && loginResponse.finalKeyData.privKey) {
if (loginResponse.metadata.typeOfUser === "v1") {
throw CoreKitError.invalidConfig("Cannot register existing SFA key for v1 users, please contact web3auth support.");
}
const existingSFAKey = loginResponse.finalKeyData.privKey.padStart(64, "0");
await this.setupTkey({
providedImportKey: existingSFAKey,
sfaLoginResponse: loginResponse,
userInfo,
importingSFAKey: true,
persistSessionSigs: true
});
} else {
await this.setupTkey({
providedImportKey: importTssKey,
sfaLoginResponse: loginResponse,
userInfo,
importingSFAKey: true,
persistSessionSigs: true
});
}
} catch (err) {
log.error("login error", err);
if (err instanceof CoreError) {
if (err.code === 1302) {
throw CoreKitError.default(ERRORS.TKEY_SHARES_REQUIRED);
}
}
throw CoreKitError.default(err.message);
}
}
async loginWithJWT(params) {
this.checkReady();
const {
prefetchTssPublicKeys = 1
} = params;
if (prefetchTssPublicKeys > 3) {
throw CoreKitError.prefetchValueExceeded(`The prefetch value '${prefetchTssPublicKeys}' exceeds the maximum allowed limit of 3.`);
}
const {
verifier,
verifierId,
idToken,
importTssKey,
registerExistingSFAKey
} = params;
this.torusSp.verifierName = verifier;
this.torusSp.verifierId = verifierId;
if (registerExistingSFAKey && importTssKey) {
throw CoreKitError.invalidConfig("Cannot import TSS key and register SFA key at the same time.");
}
try {
// prefetch tss pub keys.
const prefetchTssPubs = [];
for (let i = 0; i < prefetchTssPublicKeys; i++) {
prefetchTssPubs.push(this.torusSp.getTSSPubKey(this.tkey.tssTag, i));
}
// get postbox key.
let loginPromise;
if (!params.subVerifier) {
// single verifier login.
loginPromise = this.torusSp.customAuthInstance.getTorusKey(verifier, verifierId, {
verifier_id: verifierId
}, idToken, _objectSpread(_objectSpread({}, params.extraVerifierParams), params.additionalParams));
} else {
// aggregate verifier login
loginPromise = this.torusSp.customAuthInstance.getAggregateTorusKey(verifier, verifierId, [{
verifier: params.subVerifier,
idToken,
extraVerifierParams: params.extraVerifierParams
}]);
}
// wait for prefetch completed before setup tkey
const [loginResponse] = await Promise.all([loginPromise, ...prefetchTssPubs]);
if (registerExistingSFAKey && loginResponse.finalKeyData.privKey) {
if (loginResponse.metadata.typeOfUser === "v1") {
throw CoreKitError.invalidConfig("Cannot register existing SFA key for v1 users, please contact web3auth support.");
}
const existingSFAKey = loginResponse.finalKeyData.privKey.padStart(64, "0");
await this.setupTkey({
providedImportKey: existingSFAKey,
importingSFAKey: true,
sfaLoginResponse: loginResponse,
userInfo: _objectSpread(_objectSpread({}, parseToken(idToken)), {}, {
verifier,
verifierId
}),
persistSessionSigs: true
});
} else {
await this.setupTkey({
providedImportKey: importTssKey,
importingSFAKey: false,
sfaLoginResponse: loginResponse,
userInfo: _objectSpread(_objectSpread({}, parseToken(idToken)), {}, {
verifier,
verifierId
}),
persistSessionSigs: true
});
}
} catch (err) {
log.error("login error", err);
if (err instanceof CoreError) {
if (err.code === 1302) {
const newError = CoreKitError.default(ERRORS.TKEY_SHARES_REQUIRED);
newError.stack = err.stack;
throw newError;
}
}
const newError = CoreKitError.default(err.message);
newError.stack = err.stack;
throw newError;
}
}
async handleRedirectResult() {
this.checkReady();
try {
const result = await this.torusSp.customAuthInstance.getRedirectResult();
let loginResponse;
let userInfo;
if (result.method === TORUS_METHOD.TRIGGER_LOGIN) {
loginResponse = result.result;
if (!loginResponse) {
throw CoreKitError.invalidTorusLoginResponse();
}
userInfo = loginResponse.userInfo;
this.torusSp.verifierName = userInfo.verifier;
} else if (result.method === TORUS_METHOD.TRIGGER_AGGREGATE_LOGIN) {
loginResponse = result.result;
if (!loginResponse) {
throw CoreKitError.invalidTorusAggregateLoginResponse();
}
userInfo = loginResponse.userInfo[0];
this.torusSp.verifierName = userInfo.aggregateVerifier;
} else {
throw CoreKitError.unsupportedRedirectMethod();
}
this.torusSp.postboxKey = new BN(this.state.postBoxKey, "hex");
this.torusSp.verifierId = userInfo.verifierId;
await this.setupTkey({
importingSFAKey: false,
userInfo,
sfaLoginResponse: loginResponse,
persistSessionSigs: true
});
} catch (error) {
this.resetState();
log.error("error while handling redirect result", error);
throw CoreKitError.default(error.message);
}
}
async inputFactorKey(factorKey) {
this.checkReady();
try {
// input tkey device share when required share > 0 ( or not reconstructed )
// assumption tkey shares will not changed
if (!this.tKey.secp256k1Key) {
const factorKeyMetadata = await this.getFactorKeyMetadata(factorKey);
await this.tKey.inputShareStoreSafe(factorKeyMetadata, true);
}
// Finalize initialization.
await this.tKey.reconstructKey();
await this.finalizeTkey(factorKey);
} catch (err) {
log.error("login error", err);
if (err instanceof CoreError) {
if (err.code === 1302) {
throw CoreKitError.default(ERRORS.TKEY_SHARES_REQUIRED);
}
}
throw CoreKitError.default(err.message);
}
}
async setTssWalletIndex(accountIndex, accountName) {
const tssPubKey = this.tKey.getTSSPub(accountIndex).toSEC1(this.tkey.tssCurve, false);
// Retrieve the existing general store domain data
const generalStoreDomain = this.tkey.metadata.getGeneralStoreDomain("tssWalletIndex");
let tssWalletIndex = {};
if (generalStoreDomain) {
tssWalletIndex = JSON.parse(generalStoreDomain);
}
// Check if the account index is already present
if (!tssWalletIndex[accountIndex.toString()]) {
tssWalletIndex[accountIndex.toString()] = {
pubKey: tssPubKey.toString("hex"),
name: accountName || ""
};
}
this.tkey.metadata.setGeneralStoreDomain("ts