'use strict';

var core = require('#internal/core');
var core$1 = require('@dynamic-labs-wallet/core');
var node = require('#internal/node');
var logger = require('@dynamic-labs/logger');
var forwardMpcClient = require('@dynamic-labs-wallet/forward-mpc-client');
var uuid = require('uuid');
var crypto = require('crypto');
require('node:crypto');

// Removed duplicate exports - these are already exported from #internal/core
const getMPCSignatureScheme = ({ signingAlgorithm, baseRelayUrl = core$1.MPC_RELAY_PROD_API_URL })=>{
    switch(signingAlgorithm){
        case core$1.SigningAlgorithm.ECDSA:
            return new node.Ecdsa(baseRelayUrl);
        case core$1.SigningAlgorithm.ED25519:
            return new node.ExportableEd25519(baseRelayUrl);
        case core$1.SigningAlgorithm.BIP340:
            return new node.BIP340(baseRelayUrl);
        default:
            throw new Error(`Unsupported signing algorithm: ${signingAlgorithm}`);
    }
};
const getMPCSigner = ({ chainName, baseRelayUrl, bitcoinConfig })=>{
    const chainConfig = core$1.getMPCChainConfig(chainName, bitcoinConfig);
    const signatureScheme = getMPCSignatureScheme({
        signingAlgorithm: chainConfig.signingAlgorithm,
        baseRelayUrl
    });
    return signatureScheme;
};

function _extends() {
    _extends = Object.assign || function assign(target) {
        for(var i = 1; i < arguments.length; i++){
            var source = arguments[i];
            for(var key in source)if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key];
        }
        return target;
    };
    return _extends.apply(this, arguments);
}

const createLogError = (clientTag)=>({ message, error, context })=>logError({
            message,
            error,
            context,
            clientTag
        });
const logError = ({ message, error, context, clientTag = 'node' })=>{
    if (core$1.isAxiosError(error)) {
        core$1.handleAxiosError(error, message, context);
        return;
    }
    core$1.Logger.error(`[DynamicWaasWalletClient] Error in ${clientTag} client`, {
        message,
        error: error instanceof Error ? error.message : String(error),
        context
    });
};
const bytesToBase64 = (arr)=>{
    return btoa(Array.from(arr, (b)=>String.fromCharCode(b)).join(''));
};
const stringToBytes = (str)=>{
    return new TextEncoder().encode(str);
};
const base64ToBytes = (base64)=>{
    return new Uint8Array(Buffer.from(base64, 'base64'));
};
// Helper function to ensure proper base64 padding
const ensureBase64Padding = (str)=>{
    return str.padEnd(Math.ceil(str.length / 4) * 4, '=');
};
const isHexString = (str)=>{
    // Remove 0x prefix if present
    const hex = str.startsWith('0x') ? str.slice(2) : str;
    // Check if string contains only hex characters
    return /^[0-9A-Fa-f]+$/.test(hex);
};
const getExternalServerKeyShareBackupInfo = (params)=>{
    var _params_walletProperties, _params_walletProperties_keyShares_;
    const backups = {
        [core$1.BackupLocation.DYNAMIC]: [],
        [core$1.BackupLocation.GOOGLE_DRIVE]: [],
        [core$1.BackupLocation.ICLOUD]: [],
        [core$1.BackupLocation.USER]: [],
        [core$1.BackupLocation.EXTERNAL]: [],
        [core$1.BackupLocation.DELEGATED]: []
    };
    if (!(params == null ? void 0 : (_params_walletProperties = params.walletProperties) == null ? void 0 : _params_walletProperties.keyShares)) {
        return {
            backups,
            passwordEncrypted: false
        };
    }
    params.walletProperties.keyShares.forEach((keyShare)=>{
        if (backups[keyShare.backupLocation]) {
            backups[keyShare.backupLocation].push({
                location: keyShare.backupLocation,
                id: keyShare.id,
                keygenId: keyShare.keygenId,
                externalKeyShareId: keyShare.externalKeyShareId,
                passwordEncrypted: keyShare.passwordEncrypted
            });
        }
    });
    const passwordEncrypted = Boolean((_params_walletProperties_keyShares_ = params.walletProperties.keyShares[0]) == null ? void 0 : _params_walletProperties_keyShares_.passwordEncrypted);
    return {
        backups,
        passwordEncrypted
    };
};
/**
 * Helper function to merge keyshares and remove duplicates based on pubkey and secretShare
 * @param existingKeyShares - Array of existing keyshares
 * @param newKeyShares - Array of new keyshares to merge
 * @returns Array of merged unique keyshares
 */ const mergeUniqueKeyShares = (existingKeyShares, newKeyShares)=>{
    const uniqueKeyShares = newKeyShares.filter((newShare)=>!existingKeyShares.some((existingShare)=>{
            if (!(newShare == null ? void 0 : newShare.pubkey) || !(existingShare == null ? void 0 : existingShare.pubkey)) return false;
            return newShare.pubkey.toString() === existingShare.pubkey.toString() && newShare.secretShare === existingShare.secretShare;
        }));
    return [
        ...existingKeyShares,
        ...uniqueKeyShares
    ];
};
/**
 * Generic helper function to retry a promise-based operations
 *
 * @param operation - The async operation to retry
 * @param config - Configuration options for retry behavior
 * @returns Promise with the operation result
 * @throws Last error encountered after all retries are exhausted
 */ async function retryPromise(operation, { maxAttempts = 5, retryInterval = 500, operationName = 'operation', logContext = {} } = {}) {
    let attempts = 0;
    while(attempts < maxAttempts){
        try {
            return await operation();
        } catch (error) {
            attempts++;
            if (attempts === maxAttempts) {
                core$1.Logger.error(`Failed to execute ${operationName} after ${maxAttempts} attempts`, _extends({}, logContext, {
                    error
                }));
                throw error;
            }
            await new Promise((resolve)=>setTimeout(resolve, retryInterval));
        }
    }
    // TypeScript needs this even though it's unreachable
    throw new Error('Unreachable code');
}
const formatEvmMessage = (message)=>{
    if (typeof message === 'string' && message.startsWith('0x')) {
        const serializedTxBytes = Uint8Array.from(Buffer.from(message.slice(2), 'hex'));
        return node.MessageHash.keccak256(serializedTxBytes);
    }
    return node.MessageHash.keccak256(message);
};
const formatSolanaMessage = (message)=>{
    if (typeof message === 'string') {
        if (!isHexString(message)) {
            return Buffer.from(message).toString('hex');
        } else {
            return new Uint8Array(Buffer.from(message, 'hex'));
        }
    } else {
        return message;
    }
};
const formatTonMessage = (message)=>{
    if (typeof message === 'string') {
        if (!isHexString(message)) {
            return Buffer.from(message).toString('hex');
        } else {
            return new Uint8Array(Buffer.from(message, 'hex'));
        }
    } else {
        return message;
    }
};
const formatMessage = (chainName, message)=>{
    switch(chainName){
        case 'EVM':
            return formatEvmMessage(message);
        case 'SVM':
            return formatSolanaMessage(message);
        case 'SUI':
            return message;
        case 'TON':
            return formatTonMessage(message);
        default:
            throw new Error('Unsupported chain name');
    }
};

const ENCRYPTION_VERSION_LEGACY = 'v1';
const ENCRYPTION_VERSION_CURRENT = 'v2';
const PBKDF2_ALGORITHM = 'PBKDF2';
const PBKDF2_HASH_ALGORITHM = 'SHA-256';
const AES_GCM_ALGORITHM = 'AES-GCM';
const AES_GCM_LENGTH = 256;
const ENCRYPTION_VERSIONS = {
    [ENCRYPTION_VERSION_LEGACY]: {
        version: ENCRYPTION_VERSION_LEGACY,
        algorithm: AES_GCM_ALGORITHM,
        keyDerivation: PBKDF2_ALGORITHM,
        iterations: 100000,
        hashAlgorithm: PBKDF2_HASH_ALGORITHM,
        algorithmLength: AES_GCM_LENGTH
    },
    [ENCRYPTION_VERSION_CURRENT]: {
        version: ENCRYPTION_VERSION_CURRENT,
        algorithm: AES_GCM_ALGORITHM,
        keyDerivation: PBKDF2_ALGORITHM,
        iterations: 1000000,
        hashAlgorithm: PBKDF2_HASH_ALGORITHM,
        algorithmLength: AES_GCM_LENGTH
    }
};
ENCRYPTION_VERSIONS[ENCRYPTION_VERSION_CURRENT].iterations;
ENCRYPTION_VERSIONS[ENCRYPTION_VERSION_LEGACY].iterations;
const getKey = async ({ password, salt, encryptionConfig })=>{
    const passwordBytes = stringToBytes(password);
    const initialKey = await crypto.subtle.importKey('raw', passwordBytes, {
        name: 'PBKDF2'
    }, false, [
        'deriveKey'
    ]);
    return crypto.subtle.deriveKey({
        name: encryptionConfig.keyDerivation,
        salt: salt,
        iterations: encryptionConfig.iterations,
        hash: encryptionConfig.hashAlgorithm
    }, initialKey, {
        name: encryptionConfig.algorithm,
        length: encryptionConfig.algorithmLength
    }, false, [
        'encrypt',
        'decrypt'
    ]);
};
/**
 * Encrypts data using the specified encryption version.
 * Always uses the latest encryption configuration for new encryptions by default.
 */ const encryptData = async ({ data, password, version = ENCRYPTION_VERSION_CURRENT })=>{
    const encryptionConfig = ENCRYPTION_VERSIONS[version];
    if (!encryptionConfig) {
        throw new Error(`Unsupported encryption version: ${version}`);
    }
    try {
        // Generate a random salt and IV
        const salt = crypto.getRandomValues(new Uint8Array(16));
        const iv = crypto.getRandomValues(new Uint8Array(12)); // AES-GCM requires 12 bytes
        const key = await getKey({
            password,
            salt,
            encryptionConfig
        });
        // Convert the input string to bytes
        const dataBytes = new TextEncoder().encode(data);
        // Encrypt the data
        const encryptedData = await crypto.subtle.encrypt({
            name: AES_GCM_ALGORITHM,
            iv
        }, key, dataBytes);
        // Convert to base64 strings, ensure proper padding
        return {
            salt: bytesToBase64(salt),
            iv: bytesToBase64(iv),
            cipher: bytesToBase64(new Uint8Array(encryptedData)),
            version
        };
    } catch (e) {
        throw new Error('Error encrypting data');
    }
};
/**
 * Decrypts data with version-based configuration.
 * Uses the version field from the data to determine encryption parameters.
 * Falls back to legacy version for backward compatibility if no version is specified.
 */ const decryptData = async ({ data, password })=>{
    const { salt, iv, cipher, version } = data;
    // Ensure proper base64 padding for all values
    const paddedSalt = ensureBase64Padding(salt);
    const paddedIv = ensureBase64Padding(iv);
    const paddedCipher = ensureBase64Padding(cipher);
    const saltBytes = base64ToBytes(paddedSalt);
    const ivBytes = base64ToBytes(paddedIv);
    const cipherBytes = base64ToBytes(paddedCipher);
    let encryptionConfig;
    // Use version-based configuration if available, otherwise fallback to legacy
    if (version && ENCRYPTION_VERSIONS[version]) {
        encryptionConfig = ENCRYPTION_VERSIONS[version];
    } else {
        // Fallback to legacy version for backward compatibility
        encryptionConfig = ENCRYPTION_VERSIONS[ENCRYPTION_VERSION_LEGACY];
    }
    try {
        const key = await getKey({
            password,
            salt: saltBytes,
            encryptionConfig
        });
        const decryptedData = await crypto.subtle.decrypt({
            name: AES_GCM_ALGORITHM,
            iv: ivBytes
        }, key, cipherBytes);
        return new TextDecoder().decode(decryptedData);
    } catch (error) {
        throw new Error('Decryption failed: ' + error);
    }
};

class DynamicWalletClient {
    ensureApiClientAuthenticated() {
        if (!this.isApiClientAuthenticated) {
            throw new Error('Client must be authenticated before making API calls. Call authenticateApiToken first.');
        }
    }
    async authenticateApiToken(authToken) {
        const tmpClient = new core$1.DynamicApiClient({
            environmentId: this.environmentId,
            authToken,
            baseApiUrl: this.baseApiUrl,
            logger: this.logger
        });
        const response = await tmpClient.authenticateApiToken({
            environmentId: this.environmentId
        });
        const jwtTokenAuth = response.data.encodedJwts.minifiedJwt;
        this.baseJWTAuthToken = jwtTokenAuth;
        this.apiClient = new core$1.DynamicApiClient({
            environmentId: this.environmentId,
            authToken: jwtTokenAuth,
            baseApiUrl: this.baseApiUrl,
            forwardMPCClient: this.resolvedForwardMPCClient,
            logger: this.logger
        });
        this.isApiClientAuthenticated = true;
    }
    async dynamicServerInitializeKeyGen({ chainName, externalServerKeygenIds, thresholdSignatureScheme, dynamicRequestId, skipLock, bitcoinConfig, onError, onCeremonyComplete }) {
        this.ensureApiClientAuthenticated();
        try {
            const data = await this.apiClient.createWalletAccount({
                chainName,
                clientKeygenIds: externalServerKeygenIds,
                thresholdSignatureScheme,
                dynamicRequestId,
                skipLock,
                bitcoinConfig,
                onError,
                onCeremonyComplete
            });
            return data;
        } catch (error) {
            this.logger.error('Error in dynamicServerInitializeKeyGen', error);
            throw new Error('Error creating wallet account in dynamicServerInitializeKeyGen');
        }
    }
    async externalServerInitializeKeyGen({ chainName, thresholdSignatureScheme, bitcoinConfig }) {
        try {
            // Get the mpc signer
            const mpcSigner = getMPCSigner({
                chainName,
                baseRelayUrl: this.baseMPCRelayApiUrl,
                bitcoinConfig
            });
            const clientThreshold = core$1.getClientThreshold(thresholdSignatureScheme);
            const keygenInitResults = await Promise.all(Array(clientThreshold).fill(null).map(()=>mpcSigner.initKeygen()));
            return keygenInitResults;
        } catch (error) {
            this.logger.error('Error in externalServerInitializeKeyGen', error);
            throw new Error('Error initializing keygen in externalServerInitializeKeyGen');
        }
    }
    async derivePublicKey({ chainName, keyShare, derivationPath, bitcoinConfig }) {
        try {
            const mpcSigner = getMPCSigner({
                chainName,
                baseRelayUrl: this.baseMPCRelayApiUrl,
                bitcoinConfig
            });
            let publicKey;
            if (mpcSigner instanceof node.Ecdsa) {
                publicKey = await mpcSigner.derivePubkey(keyShare, derivationPath);
            } else if (mpcSigner instanceof node.ExportableEd25519) {
                publicKey = await mpcSigner.getPubkey(keyShare);
            } else if (mpcSigner instanceof node.BIP340) {
                publicKey = await mpcSigner.deriveTweakPubkey(keyShare, derivationPath);
            }
            return publicKey;
        } catch (error) {
            this.logger.error('Error in derivePublicKey', error);
            throw new Error('Error deriving public key in derivePublicKey');
        }
    }
    async forwardMPCExternalServerKeyGen({ chainName, roomId, dynamicServerKeygenIds, externalServerInitKeygenResults, thresholdSignatureScheme, bitcoinConfig }) {
        try {
            const chainConfig = core$1.getMPCChainConfig(chainName, bitcoinConfig);
            const signingAlgo = chainConfig.signingAlgorithm;
            const mpcConfig = core$1.MPC_CONFIG[thresholdSignatureScheme];
            const isEd25519 = typeof signingAlgo === 'string' && signingAlgo.toLowerCase().includes('ed25519');
            const serverKeygenResults = await Promise.all(externalServerInitKeygenResults.map(async (currentInit)=>{
                const otherExternalServerKeygenIds = externalServerInitKeygenResults.filter((init)=>init.keygenId !== currentInit.keygenId).map((init)=>init.keygenId);
                const allOtherKeygenIds = [
                    ...dynamicServerKeygenIds,
                    ...otherExternalServerKeygenIds
                ];
                const keygenMethod = isEd25519 ? this.apiClient.forwardMPCClient.receiveKey.bind(this.apiClient.forwardMPCClient) : this.apiClient.forwardMPCClient.keygen.bind(this.apiClient.forwardMPCClient);
                return await keygenMethod({
                    roomUuid: roomId,
                    signingAlgo,
                    numParties: mpcConfig.numberOfParties,
                    threshold: mpcConfig.threshold,
                    keygenInit: {
                        keygenId: currentInit.keygenId,
                        keygenSecret: currentInit.keygenSecret
                    },
                    keygenIds: allOtherKeygenIds,
                    relayDomain: this.baseMPCRelayApiUrl || '',
                    environmentId: this.environmentId
                });
            }));
            const [serverKeygenResult] = serverKeygenResults;
            const chainConfigForDeriv = core$1.getMPCChainConfig(chainName, bitcoinConfig);
            const derivationPath = new Uint32Array(chainConfigForDeriv.derivationPath);
            const rawPublicKey = await this.derivePublicKey({
                chainName,
                keyShare: serverKeygenResult,
                derivationPath,
                bitcoinConfig
            });
            return {
                rawPublicKey,
                externalServerKeyGenResults: serverKeygenResults
            };
        } catch (error) {
            this.logger.error('Error during forward MPC external server keygen', {
                error,
                chainName,
                environmentId: this.environmentId
            });
            throw error;
        } finally{
            this.apiClient.forwardMPCClient.disconnect();
        }
    }
    async externalServerKeyGen({ chainName, roomId, dynamicServerKeygenIds, externalServerInitKeygenResults, thresholdSignatureScheme, bitcoinConfig }) {
        if (this.forwardMPCEnabled) {
            return this.forwardMPCExternalServerKeyGen({
                chainName,
                roomId,
                dynamicServerKeygenIds,
                externalServerInitKeygenResults,
                thresholdSignatureScheme,
                bitcoinConfig
            });
        }
        try {
            // Get the chain config and the mpc signer
            const mpcSigner = getMPCSigner({
                chainName,
                baseRelayUrl: this.baseMPCRelayApiUrl,
                bitcoinConfig
            });
            // Get the MPC config for the threshold signature scheme
            const mpcConfig = core$1.MPC_CONFIG[thresholdSignatureScheme];
            // For each client keygen init result, create an array of other parties' keygenIds
            const serverKeygenResults = await Promise.all(externalServerInitKeygenResults.map((currentInit)=>{
                // Get all other client keygenIds (excluding current one)
                const otherExternalServerKeygenIds = externalServerInitKeygenResults.filter((init)=>init.keygenId !== currentInit.keygenId).map((init)=>init.keygenId);
                // Combine server keygenIds with other client keygenIds
                const allOtherKeygenIds = [
                    ...dynamicServerKeygenIds,
                    ...otherExternalServerKeygenIds
                ];
                if (!(mpcSigner instanceof node.ExportableEd25519)) {
                    return mpcSigner.keygen(roomId, mpcConfig.numberOfParties, mpcConfig.threshold, currentInit, allOtherKeygenIds);
                } else {
                    // One party joins the keygen room using acting as the sampler: (wallet-service)
                    // The remaining parties join the key sampling ceremony using: (browser)
                    return mpcSigner.receiveKey(roomId, mpcConfig.numberOfParties, mpcConfig.threshold, currentInit, allOtherKeygenIds);
                }
            }));
            // only need one client keygen result to derive the public key
            const [serverKeygenResult] = serverKeygenResults;
            const chainConfig = core$1.getMPCChainConfig(chainName, bitcoinConfig);
            const derivationPath = new Uint32Array(chainConfig.derivationPath);
            const rawPublicKey = await this.derivePublicKey({
                chainName,
                keyShare: serverKeygenResult,
                derivationPath,
                bitcoinConfig
            });
            return {
                rawPublicKey,
                externalServerKeyGenResults: serverKeygenResults
            };
        } catch (error) {
            this.logger.error('Error in externalServerKeyGen', error);
            throw new Error('Error deriving public key in externalServerKeyGen');
        }
    }
    async keyGen({ chainName, thresholdSignatureScheme, skipLock, bitcoinConfig, onError, onCeremonyComplete }) {
        const dynamicRequestId = uuid.v4();
        try {
            const externalServerInitKeygenResults = await this.externalServerInitializeKeyGen({
                chainName,
                thresholdSignatureScheme,
                bitcoinConfig
            });
            const externalServerKeygenIds = externalServerInitKeygenResults.map((result)=>result.keygenId);
            const { roomId, serverKeygenIds: dynamicServerKeygenIds } = await this.dynamicServerInitializeKeyGen({
                chainName,
                externalServerKeygenIds,
                dynamicRequestId,
                thresholdSignatureScheme,
                skipLock,
                bitcoinConfig,
                onCeremonyComplete
            });
            const { rawPublicKey, externalServerKeyGenResults } = await this.externalServerKeyGen({
                chainName,
                roomId,
                dynamicServerKeygenIds,
                externalServerInitKeygenResults,
                thresholdSignatureScheme,
                bitcoinConfig
            });
            return {
                rawPublicKey,
                externalServerKeyShares: externalServerKeyGenResults
            };
        } catch (error) {
            this.logger.error('Error in keyGen', error);
            throw new Error('Error creating wallet account in keyGen');
        }
    }
    async importRawPrivateKey({ chainName, privateKey, thresholdSignatureScheme, bitcoinConfig, onError, onCeremonyComplete }) {
        this.ensureApiClientAuthenticated();
        const dynamicRequestId = uuid.v4();
        const mpcSigner = getMPCSigner({
            chainName,
            baseRelayUrl: this.baseMPCRelayApiUrl,
            bitcoinConfig
        });
        const externalServerKeygenInitResults = await this.externalServerInitializeKeyGen({
            chainName,
            thresholdSignatureScheme,
            bitcoinConfig
        });
        const externalServerKeygenIds = externalServerKeygenInitResults.map((result)=>result.keygenId);
        const { roomId, serverKeygenIds: dynamicServerKeygenIds } = await this.apiClient.importPrivateKey({
            chainName,
            clientKeygenIds: externalServerKeygenIds,
            thresholdSignatureScheme,
            bitcoinConfig,
            dynamicRequestId,
            onError,
            onCeremonyComplete
        });
        const { threshold } = core$1.getTSSConfig(thresholdSignatureScheme);
        const externalServerKeygenResults = await Promise.all(externalServerKeygenInitResults.map(async (currentInit, index)=>{
            const otherExternalServerKeygenIds = externalServerKeygenInitResults.filter((init)=>init.keygenId !== currentInit.keygenId).map((init)=>init.keygenId);
            if (index === 0) {
                const otherKeyGenIds = [
                    ...dynamicServerKeygenIds,
                    ...otherExternalServerKeygenIds
                ];
                const importerKeygenResult = await mpcSigner.importPrivateKeyImporter(roomId, threshold, privateKey, currentInit, otherKeyGenIds);
                return importerKeygenResult;
            } else {
                const recipientKeygenResult = await mpcSigner.importPrivateKeyRecipient(roomId, threshold, currentInit, [
                    ...dynamicServerKeygenIds,
                    ...otherExternalServerKeygenIds
                ]);
                return recipientKeygenResult;
            }
        }));
        const [externalServerKeygenResult] = externalServerKeygenResults;
        const rawPublicKey = await this.derivePublicKey({
            chainName,
            keyShare: externalServerKeygenResult,
            derivationPath: undefined,
            bitcoinConfig
        });
        return {
            rawPublicKey,
            externalServerKeyShares: externalServerKeygenResults
        };
    }
    async dynamicServerSign({ walletId, message, isFormatted, context, bitcoinConfig, onError }) {
        const dynamicRequestId = uuid.v4();
        this.ensureApiClientAuthenticated();
        // Create the room and sign the message
        if (typeof message !== 'string') {
            message = '0x' + Buffer.from(message).toString('hex');
        }
        const data = await this.apiClient.signMessage({
            walletId,
            message,
            isFormatted,
            dynamicRequestId,
            context: context ? JSON.parse(JSON.stringify(context, (_key, value)=>typeof value === 'bigint' ? value.toString() : value)) : undefined,
            onError,
            forwardMPCClientEnabled: this.forwardMPCEnabled,
            bitcoinConfig
        });
        return data;
    }
    async externalServerSign({ chainName, message, roomId, keyShare, derivationPath, isFormatted, bitcoinConfig }) {
        try {
            const mpcSigner = getMPCSigner({
                chainName,
                baseRelayUrl: this.baseMPCRelayApiUrl,
                bitcoinConfig
            });
            const formattedMessage = isFormatted ? new node.MessageHash(message) : formatMessage(chainName, message);
            const tweak = bitcoinConfig == null ? void 0 : bitcoinConfig.tweak;
            const signature = await mpcSigner.sign(roomId, keyShare, formattedMessage, derivationPath, tweak);
            return signature;
        } catch (error) {
            this.logger.error('Error in externalServerSign', error);
            throw error;
        }
    }
    async forwardMPCClientSign({ chainName, message, roomId, keyShare, derivationPath, formattedMessage, dynamicRequestId, isFormatted }) {
        try {
            const messageForForwardMPC = core$1.serializeMessageForForwardMPC({
                message,
                isFormatted,
                chainName
            });
            this.logger.debug('Signing message with MPC Socket Client');
            const environment = core$1.getEnvironmentFromUrl(this.baseApiUrl);
            const defaultRelayUrl = core$1.MPC_RELAY_URL_MAP[environment];
            const { signature: signatureBytes } = await this.apiClient.forwardMPCClient.signMessage({
                keyshare: keyShare,
                message: chainName === 'SVM' ? formattedMessage : messageForForwardMPC,
                relayDomain: this.baseMPCRelayApiUrl || defaultRelayUrl,
                signingAlgo: chainName === 'EVM' ? 'ECDSA' : 'ED25519',
                hashAlgo: chainName === 'EVM' && !isFormatted ? 'keccak256' : undefined,
                derivationPath: derivationPath,
                roomUuid: roomId
            });
            if (!(signatureBytes instanceof Uint8Array)) {
                throw new TypeError(`Invalid signature format: expected Uint8Array, got ${typeof signatureBytes}`);
            }
            // Convert to EcdsaSignature
            if (chainName === 'EVM') {
                const ecdsaSignature = node.EcdsaSignature.fromBuffer(signatureBytes);
                return ecdsaSignature;
            } else {
                return signatureBytes;
            }
        } catch (error) {
            this.logger.error('Error signing message with forward MPC client', {
                error,
                environmentId: this.environmentId,
                dynamicRequestId
            });
            throw error;
        } finally{
            this.apiClient.forwardMPCClient.disconnect();
        }
    }
    async sign({ accountAddress, externalServerKeyShares, message, chainName, password = undefined, isFormatted = false, context, onError, bitcoinConfig }) {
        try {
            await this.verifyPassword({
                accountAddress,
                password
            });
            const wallet = await this.getWallet({
                accountAddress,
                walletOperation: core$1.WalletOperation.SIGN_MESSAGE,
                password
            });
            externalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : wallet.externalServerKeyShares;
            if (!externalServerKeyShares) {
                var _wallet_externalServerKeySharesBackupInfo;
                const hasExternalKeyShareId = Object.values(((_wallet_externalServerKeySharesBackupInfo = wallet.externalServerKeySharesBackupInfo) == null ? void 0 : _wallet_externalServerKeySharesBackupInfo.backups) || {}).some((locations)=>locations.some((loc)=>loc.location === core$1.BackupLocation.EXTERNAL));
                const errorMessage = 'External server key shares are required to sign a message';
                if (hasExternalKeyShareId) {
                    this.logger.error(errorMessage);
                } else {
                    this.logger.warn(errorMessage);
                }
                throw new Error(errorMessage);
            }
            // Perform the dynamic server sign
            const data = await this.dynamicServerSign({
                walletId: wallet.walletId,
                message,
                isFormatted,
                context,
                bitcoinConfig,
                onError
            });
            const derivationPath = wallet.derivationPath && wallet.derivationPath != '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
            // Perform the external server sign and return the signature
            if (this.forwardMPCEnabled) {
                const formattedMessage = isFormatted ? new node.MessageHash(message) : formatMessage(chainName, message);
                const signature = await this.forwardMPCClientSign({
                    chainName,
                    message,
                    roomId: data.roomId,
                    keyShare: externalServerKeyShares[0],
                    derivationPath,
                    formattedMessage,
                    dynamicRequestId: uuid.v4(),
                    isFormatted
                });
                return signature;
            } else {
                const signature = await this.externalServerSign({
                    chainName,
                    message,
                    roomId: data.roomId,
                    keyShare: externalServerKeyShares[0],
                    derivationPath,
                    isFormatted,
                    bitcoinConfig
                });
                return signature;
            }
        } catch (error) {
            if (!(error instanceof Error && error.message === 'External server key shares are required to sign a message')) {
                this.logger.error('Error in sign', error);
            }
            throw error;
        }
    }
    async refreshWalletAccountShares({ accountAddress, chainName, password = undefined, externalServerKeyShares, backUpToClientShareService = false }) {
        this.ensureApiClientAuthenticated();
        await this.verifyPassword({
            accountAddress,
            password
        });
        const wallet = await this.getWallet({
            accountAddress,
            walletOperation: core$1.WalletOperation.REFRESH,
            password
        });
        const mpcSigner = getMPCSigner({
            chainName,
            baseRelayUrl: this.baseMPCRelayApiUrl
        });
        // Create the room and refresh the shares
        const data = await this.apiClient.refreshWalletAccountShares({
            walletId: wallet.walletId
        });
        const roomId = data.roomId;
        externalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : wallet.externalServerKeyShares;
        if (!externalServerKeyShares) {
            throw new Error('External server key shares are required to refresh');
        }
        const refreshResults = await Promise.all(externalServerKeyShares.map((serverKeyShare)=>mpcSigner.refresh(roomId, serverKeyShare)));
        this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
            externalServerKeyShares: refreshResults,
            externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo()
        });
        await this.storeEncryptedBackupByWallet({
            accountAddress,
            password: password != null ? password : this.environmentId,
            backUpToClientShareService
        });
        return refreshResults;
    }
    async getExportId({ chainName, serverKeyShare, bitcoinConfig }) {
        const mpcSigner = getMPCSigner({
            chainName,
            baseRelayUrl: this.baseMPCRelayApiUrl,
            bitcoinConfig
        });
        const exportId = await mpcSigner.exportID(serverKeyShare);
        return exportId;
    }
    /**
   * Helper function to create client shares required to complete a reshare ceremony.
   * @param {string} chainName - The chain to create shares for
   * @param {WalletProperties} wallet - The wallet to reshare
   * @param {ThresholdSignatureScheme} oldThresholdSignatureScheme - The current threshold signature scheme
   * @param {ThresholdSignatureScheme} newThresholdSignatureScheme - The target threshold signature scheme
   * @returns {Promise<{
   *   newClientInitKeygenResults: ClientInitKeygenResult[],
   *   newClientKeygenIds: string[],
   *   existingClientKeygenIds: string[],
   *   existingClientKeyShares: ClientKeyShare[]
   * }>} Object containing new and existing client keygen results, IDs and shares
   * @todo Support higher to lower reshare strategies
   */ async reshareStrategy({ chainName, wallet, oldThresholdSignatureScheme, newThresholdSignatureScheme }) {
        // Derive bitcoinConfig for BTC wallets
        const bitcoinConfig = chainName === 'BTC' && wallet.addressType ? {
            addressType: wallet.addressType
        } : undefined;
        const mpcSigner = getMPCSigner({
            chainName,
            baseRelayUrl: this.baseMPCRelayApiUrl,
            bitcoinConfig
        });
        // Determine share counts based on threshold signature schemes
        const { newExternalServerShareCount, existingExternalServerShareCount } = core$1.getServerWalletReshareConfig({
            oldThresholdSignatureScheme,
            newThresholdSignatureScheme
        });
        // Create new client shares
        const newExternalServerInitKeygenResults = await Promise.all(Array.from({
            length: newExternalServerShareCount
        }, ()=>mpcSigner.initKeygen()));
        const newExternalServerKeygenIds = newExternalServerInitKeygenResults.map((result)=>result.keygenId);
        // Get existing client shares
        const existingExternalServerKeyShares = wallet.externalServerKeyShares.slice(0, existingExternalServerShareCount);
        const existingExternalServerKeygenIds = await Promise.all(existingExternalServerKeyShares.map(async (keyShare)=>await this.getExportId({
                chainName,
                serverKeyShare: keyShare,
                bitcoinConfig
            })));
        return {
            newExternalServerInitKeygenResults,
            newExternalServerKeygenIds,
            existingExternalServerKeygenIds,
            existingExternalServerKeyShares
        };
    }
    async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, externalServerKeyShares, backUpToClientShareService = false }) {
        this.ensureApiClientAuthenticated();
        await this.verifyPassword({
            accountAddress,
            password
        });
        const { existingExternalServerShareCount } = core$1.getServerWalletReshareConfig({
            oldThresholdSignatureScheme,
            newThresholdSignatureScheme
        });
        const wallet = await this.getWallet({
            accountAddress,
            walletOperation: core$1.WalletOperation.RESHARE,
            shareCount: existingExternalServerShareCount,
            password
        });
        externalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : wallet.externalServerKeyShares;
        if (!externalServerKeyShares) {
            throw new Error('External server key shares are required to reshare');
        }
        const { newExternalServerInitKeygenResults, newExternalServerKeygenIds, existingExternalServerKeygenIds, existingExternalServerKeyShares } = await this.reshareStrategy({
            chainName,
            wallet: _extends({}, wallet, {
                externalServerKeyShares
            }),
            oldThresholdSignatureScheme,
            newThresholdSignatureScheme
        });
        const externalServerKeygenIds = [
            ...newExternalServerKeygenIds,
            ...existingExternalServerKeygenIds
        ];
        // Server to create the room and complete the server reshare logics
        const data = await this.apiClient.reshare({
            walletId: wallet.walletId,
            clientKeygenIds: externalServerKeygenIds,
            oldThresholdSignatureScheme,
            newThresholdSignatureScheme
        });
        const { roomId, serverKeygenIds: dynamicServerKeygenIds, newServerKeygenIds: newDynamicServerKeygenIds = [] } = data;
        // Get the MPC config for the threshold signature scheme
        const oldMpcConfig = core$1.MPC_CONFIG[oldThresholdSignatureScheme];
        const newMpcConfig = core$1.MPC_CONFIG[newThresholdSignatureScheme];
        const allPartyKeygenIds = [
            ...externalServerKeygenIds,
            ...dynamicServerKeygenIds,
            ...newDynamicServerKeygenIds
        ];
        const mpcSigner = getMPCSigner({
            chainName,
            baseRelayUrl: this.baseMPCRelayApiUrl
        });
        const reshareResults = await Promise.all([
            ...newExternalServerInitKeygenResults.map((keygenResult)=>mpcSigner.reshareNewParty(roomId, oldMpcConfig.threshold, newMpcConfig.threshold, keygenResult, allPartyKeygenIds)),
            ...existingExternalServerKeyShares.map((keyShare)=>mpcSigner.reshareRemainingParty(roomId, newMpcConfig.threshold, keyShare, allPartyKeygenIds))
        ]);
        this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
            externalServerKeyShares: reshareResults,
            externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo()
        });
        await this.storeEncryptedBackupByWallet({
            accountAddress,
            password,
            backUpToClientShareService
        });
        return reshareResults;
    }
    async exportKey({ accountAddress, chainName, password = undefined, externalServerKeyShares, bitcoinConfig, elevatedAccessToken }) {
        this.ensureApiClientAuthenticated();
        await this.verifyPassword({
            accountAddress,
            password
        });
        const wallet = await this.getWallet({
            accountAddress,
            password,
            walletOperation: core$1.WalletOperation.EXPORT_PRIVATE_KEY
        });
        externalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : wallet.externalServerKeyShares;
        if (!externalServerKeyShares) {
            throw new Error('External server key shares are required to export a private key');
        }
        const mpcSigner = getMPCSigner({
            chainName,
            baseRelayUrl: this.baseMPCRelayApiUrl,
            bitcoinConfig
        });
        const exportId = await this.getExportId({
            chainName,
            serverKeyShare: externalServerKeyShares[0],
            bitcoinConfig
        });
        const data = await this.apiClient.exportKey({
            walletId: wallet.walletId,
            exportId,
            bitcoinConfig,
            elevatedAccessToken
        });
        const keyExportRaw = await mpcSigner.exportFullPrivateKey(data.roomId, externalServerKeyShares[0], exportId);
        if (!keyExportRaw) {
            throw new Error('Error exporting private key');
        }
        const derivationPath = wallet.derivationPath && wallet.derivationPath != '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
        let derivedPrivateKey;
        if (mpcSigner instanceof node.Ecdsa) {
            derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, derivationPath);
        } else if (mpcSigner instanceof node.ExportableEd25519) {
            derivedPrivateKey = keyExportRaw;
        } else if (mpcSigner instanceof node.BIP340) {
            derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, derivationPath);
        }
        return {
            derivedPrivateKey
        };
    }
    async offlineExportKey({ chainName, keyShares, derivationPath }) {
        try {
            if (!keyShares || keyShares.length < 2) {
                throw new Error(`Must provide at least min threshold of key shares`);
            }
            const mpcSigner = getMPCSigner({
                chainName,
                baseRelayUrl: this.baseMPCRelayApiUrl
            });
            const walletKeyShares = keyShares.map((keyShare)=>{
                return mpcSigner instanceof node.Ecdsa ? new node.EcdsaKeygenResult(keyShare.pubkey, keyShare.secretShare) : mpcSigner instanceof node.ExportableEd25519 ? new node.ExportableEd25519KeygenResult(keyShare.pubkey, keyShare.secretShare) : new node.BIP340KeygenResult(keyShare.pubkey, keyShare.secretShare);
            });
            const keyExportRaw = await mpcSigner.offlineExportFullPrivateKey(walletKeyShares);
            if (!keyExportRaw) {
                throw new Error('Error exporting private key: Export returned null');
            }
            const chainConfig = core$1.getMPCChainConfig(chainName);
            const walletDerivationPath = !derivationPath ? undefined : new Uint32Array(chainConfig.derivationPath);
            let derivedPrivateKey;
            if (mpcSigner instanceof node.Ecdsa) {
                derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, walletDerivationPath);
            } else if (mpcSigner instanceof node.ExportableEd25519) {
                derivedPrivateKey = keyExportRaw;
            } else if (mpcSigner instanceof node.BIP340) {
                derivedPrivateKey = await mpcSigner.derivePrivateKeyFromXpriv(keyExportRaw, walletDerivationPath);
            }
            return {
                derivedPrivateKey
            };
        } catch (error) {
            this.logger.error('Error in offlineExportKey:', error);
            throw error;
        }
    }
    async encryptKeyShare({ keyShare, password }) {
        const serializedKeyShare = JSON.stringify(keyShare);
        const encryptedKeyShare = await encryptData({
            data: serializedKeyShare,
            password: password != null ? password : this.environmentId
        });
        // stringify the encrypted key share, convert to base64, and store it
        const serializedEncryptedKeyShare = Buffer.from(JSON.stringify(encryptedKeyShare)).toString('base64');
        return serializedEncryptedKeyShare;
    }
    async ensureCeremonyCompletionBeforeBackup({ accountAddress }) {
        let retries = 0;
        const maxRetries = 3;
        while((!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) && retries < maxRetries){
            await new Promise((resolve)=>setTimeout(resolve, 1000)); // Wait 1 second
            retries++;
        }
        if (!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) {
            throw new Error('Ceremony completion timeout');
        }
    }
    async storeEncryptedBackupByWallet({ accountAddress, externalServerKeyShares = undefined, password = undefined, backUpToClientShareService }) {
        this.ensureApiClientAuthenticated();
        //add retry logic for ceremony completion to prevent race condition
        await this.ensureCeremonyCompletionBeforeBackup({
            accountAddress
        });
        const dynamicRequestId = uuid.v4();
        try {
            const keySharesToBackup = externalServerKeyShares != null ? externalServerKeyShares : await this.getExternalServerKeyShares({
                accountAddress,
                password
            });
            if (!keySharesToBackup || keySharesToBackup.length === 0) {
                throw new Error(`Key shares not found for accountAddress: ${accountAddress}`);
            }
            const encryptedKeyShares = await Promise.all(keySharesToBackup.map((keyShare)=>this.encryptKeyShare({
                    keyShare,
                    password
                })));
            if (!this.walletMap[accountAddress] || !this.walletMap[accountAddress].walletId) {
                throw new Error(`WalletId not found for accountAddress: ${accountAddress}`);
            }
            const passwordEncryptedFlag = Boolean(password) && password !== this.environmentId;
            // Derive bitcoinConfig for BTC wallets
            const walletData = this.walletMap[accountAddress];
            const bitcoinConfig = walletData.chainName === 'BTC' && walletData.addressType ? {
                addressType: walletData.addressType
            } : undefined;
            const locations = [];
            if (backUpToClientShareService) {
                const data = await this.apiClient.storeEncryptedBackupByWallet({
                    walletId: this.walletMap[accountAddress].walletId,
                    encryptedKeyShares: encryptedKeyShares,
                    passwordEncrypted: passwordEncryptedFlag,
                    encryptionVersion: ENCRYPTION_VERSION_CURRENT,
                    requiresSignedSessionId: false,
                    dynamicRequestId
                });
                const keygenId = await this.getExportId({
                    chainName: walletData.chainName,
                    serverKeyShare: keySharesToBackup[0],
                    bitcoinConfig
                });
                locations.push({
                    location: core$1.BackupLocation.DYNAMIC,
                    externalKeyShareId: data.keyShareIds[0],
                    passwordEncrypted: passwordEncryptedFlag,
                    keygenId
                });
            } else {
                const keygenId = await this.getExportId({
                    chainName: walletData.chainName,
                    serverKeyShare: keySharesToBackup[0],
                    bitcoinConfig
                });
                locations.push({
                    location: core$1.BackupLocation.EXTERNAL,
                    passwordEncrypted: passwordEncryptedFlag,
                    keygenId
                });
            }
            const backupData = await this.apiClient.markKeySharesAsBackedUp({
                walletId: this.walletMap[accountAddress].walletId,
                locations,
                dynamicRequestId
            });
            const updatedBackupInfo = getExternalServerKeyShareBackupInfo({
                walletProperties: {
                    derivationPath: this.walletMap[accountAddress].derivationPath,
                    keyShares: backupData.locationsWithKeyShares.map((ks)=>({
                            id: ks.id,
                            keygenId: ks.keygenId,
                            backupLocation: ks.location,
                            externalKeyShareId: ks.externalKeyShareId,
                            passwordEncrypted: passwordEncryptedFlag
                        })),
                    thresholdSignatureScheme: this.walletMap[accountAddress].thresholdSignatureScheme
                }
            });
            this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
                externalServerKeySharesBackupInfo: updatedBackupInfo
            });
            return encryptedKeyShares;
        } catch (error) {
            this.logger.error('Error in storeEncryptedBackupByWallet:', {
                accountAddress,
                error,
                dynamicRequestId
            });
            throw error;
        }
    }
    async storeEncryptedBackupByWalletWithRetry({ accountAddress, externalServerKeyShares, password, backUpToClientShareService }) {
        await retryPromise(()=>this.storeEncryptedBackupByWallet({
                accountAddress,
                externalServerKeyShares,
                password,
                backUpToClientShareService
            }), {
            operationName: 'store encrypted backup',
            logContext: {
                walletAddress: accountAddress
            }
        });
    }
    async getExternalServerKeyShares({ accountAddress, password }) {
        var _wallet_externalServerKeySharesBackupInfo_backups, _wallet_externalServerKeySharesBackupInfo;
        const wallet = await this.getWallet({
            accountAddress,
            password,
            walletOperation: core$1.WalletOperation.REACH_THRESHOLD
        });
        // Check if the wallet has a dynamic backup and derive password encryption status from the first dynamic share
        const dynamicBackups = (wallet == null ? void 0 : (_wallet_externalServerKeySharesBackupInfo = wallet.externalServerKeySharesBackupInfo) == null ? void 0 : (_wallet_externalServerKeySharesBackupInfo_backups = _wallet_externalServerKeySharesBackupInfo.backups) == null ? void 0 : _wallet_externalServerKeySharesBackupInfo_backups.dynamic) || [];
        const passwordEncrypted = dynamicBackups.length > 0 ? Boolean(dynamicBackups[0].passwordEncrypted) : false;
        if (passwordEncrypted && !password) {
            throw new Error('Password is required for decryption but not provided. This backup was encrypted with a password.');
        }
        // recover the shares
        const recoveredShares = await this.recoverEncryptedBackupByWallet({
            accountAddress,
            password,
            walletOperation: core$1.WalletOperation.REACH_THRESHOLD
        });
        return recoveredShares;
    }
    async updatePassword({ accountAddress, existingPassword, newPassword, backUpToClientShareService }) {
        await this.getWallet({
            accountAddress,
            password: existingPassword,
            walletOperation: core$1.WalletOperation.REACH_ALL_PARTIES
        });
        await this.storeEncryptedBackupByWallet({
            accountAddress,
            password: newPassword,
            backUpToClientShareService
        });
    }
    async decryptKeyShare({ keyShare, password }) {
        const decodedKeyShare = JSON.parse(Buffer.from(keyShare, 'base64').toString());
        const decryptedKeyShare = await decryptData({
            data: decodedKeyShare,
            password: password != null ? password : this.environmentId
        });
        const deserializedKeyShare = JSON.parse(decryptedKeyShare);
        return deserializedKeyShare;
    }
    /**
   * Helper function to determine keyshare recovery strategy for dynamic shares.
   * For REFRESH operations, retrieves enough shares to meet the client threshold.
   * For all other operations, retrieves just 1 share.
   *
   * @param clientKeyShareBackupInfo - Information about backed up key shares
   * @param thresholdSignatureScheme - The signature scheme being used (2-of-2, 2-of-3, etc)
   * @param walletOperation - The operation being performed (REFRESH, SIGN_MESSAGE, etc)
   * @param shareCount - The number of shares to recover if specified for reshare operations
   * @returns @shares: Object mapping backup locations to arrays of share IDs to recover
   * @returns @requiredShareCount: The number of shares required to recover
   */ recoverStrategy({ externalServerKeySharesBackupInfo, thresholdSignatureScheme, walletOperation, shareCount = undefined }) {
        const { backups } = externalServerKeySharesBackupInfo;
        const { clientThreshold } = core$1.MPC_CONFIG[thresholdSignatureScheme];
        let requiredShareCount = walletOperation === core$1.WalletOperation.REFRESH || walletOperation === core$1.WalletOperation.REACH_ALL_PARTIES || walletOperation === core$1.WalletOperation.RESHARE ? clientThreshold : 1;
        // Override requiredShareCount if shareCount is provided
        if (shareCount !== undefined) {
            requiredShareCount = shareCount;
        }
        const dynamicShares = (backups[core$1.BackupLocation.DYNAMIC] || []).slice(0, requiredShareCount);
        const externalShares = (backups[core$1.BackupLocation.EXTERNAL] || []).slice(0, requiredShareCount);
        // If we have DYNAMIC shares, use those; otherwise use EXTERNAL shares
        const sharesToUse = dynamicShares.length > 0 ? dynamicShares : externalShares;
        const backupLocation = dynamicShares.length > 0 ? core$1.BackupLocation.DYNAMIC : core$1.BackupLocation.EXTERNAL;
        return {
            shares: {
                // EXTERNAL shares don't have externalKeyShareId (they're not uploaded to the API),
                // so we use their id for counting purposes instead of calling getRequiredExternalKeyShareId.
                [backupLocation]: backupLocation === core$1.BackupLocation.DYNAMIC ? sharesToUse.map(core$1.getRequiredExternalKeyShareId) : sharesToUse.map((ks)=>ks.id || '')
            },
            requiredShareCount
        };
    }
    /**
   * Attempts to recover key shares from backup if they are not provided.
   * The recovered shares will be stored in the wallet map for use in signing operations.
   * @param accountAddress - The account address to recover shares for
   * @param password - The password to decrypt the shares
   * @param walletOperation - The wallet operation being performed
   * @param externalServerKeyShares - The provided key shares (if any)
   * @param errorMessage - The error message to throw if recovery fails
   * @throws Error if recovery is needed but fails
   */ async ensureKeySharesRecovered({ accountAddress, password, walletOperation, externalServerKeyShares, errorMessage }) {
        if (!externalServerKeyShares || externalServerKeyShares.length === 0) {
            // attempt to recover dynamic keyshares if no key shares are provided
            // the shares will be used for signing in the node SDK if successful
            const recoveredShares = await this.recoverEncryptedBackupByWallet({
                accountAddress,
                password,
                walletOperation,
                storeRecoveredShares: true
            });
            // If recovery returned empty and no shares were provided, throw error
            if (!recoveredShares || recoveredShares.length === 0) {
                throw new Error(errorMessage);
            }
        }
    }
    async recoverEncryptedBackupByWallet({ accountAddress, password, walletOperation, shareCount = undefined, storeRecoveredShares = true }) {
        var _wallet_externalServerKeySharesBackupInfo;
        this.ensureApiClientAuthenticated();
        let wallet = this.walletMap[accountAddress];
        if (!wallet) {
            const fetchedWallet = await this.getWalletByAddress(accountAddress);
            if (!fetchedWallet) {
                throw new Error(`Wallet not found for address 1: ${accountAddress}`);
            }
            wallet = fetchedWallet;
        }
        this.logger.debug(`recoverEncryptedBackupByWallet wallet: ${walletOperation}`, wallet);
        const { shares } = this.recoverStrategy({
            externalServerKeySharesBackupInfo: wallet.externalServerKeySharesBackupInfo,
            thresholdSignatureScheme: wallet.thresholdSignatureScheme,
            walletOperation,
            shareCount
        });
        const dynamicKeyShareIds = shares[core$1.BackupLocation.DYNAMIC] || [];
        if (dynamicKeyShareIds.length === 0) {
            this.logger.debug('No DYNAMIC shares available for recovery');
            return [];
        }
        const data = await this.apiClient.recoverEncryptedBackupByWallet({
            walletId: wallet.walletId,
            externalKeyShareIds: dynamicKeyShareIds,
            requiresSignedSessionId: false
        });
        const dynamicKeyShares = data.keyShares.filter((keyShare)=>keyShare.encryptedAccountCredential !== null && keyShare.backupLocation === core$1.BackupLocation.DYNAMIC);
        var _wallet_externalServerKeySharesBackupInfo_passwordEncrypted;
        const isPasswordEncrypted = (_wallet_externalServerKeySharesBackupInfo_passwordEncrypted = (_wallet_externalServerKeySharesBackupInfo = wallet.externalServerKeySharesBackupInfo) == null ? void 0 : _wallet_externalServerKeySharesBackupInfo.passwordEncrypted) != null ? _wallet_externalServerKeySharesBackupInfo_passwordEncrypted : false;
        if (isPasswordEncrypted && !password) {
            throw new Error('Password is required for decryption but not provided. This backup was encrypted with a password.');
        }
        const decryptedKeyShares = await Promise.all(dynamicKeyShares.map((keyShare)=>this.decryptKeyShare({
                keyShare: keyShare.encryptedAccountCredential,
                password: password != null ? password : this.environmentId
            })));
        if (storeRecoveredShares) {
            this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
                externalServerKeyShares: mergeUniqueKeyShares(this.walletMap[accountAddress].externalServerKeyShares || [], decryptedKeyShares)
            });
        }
        return decryptedKeyShares;
    }
    async exportExternalServerKeyShares({ accountAddress, password }) {
        await this.verifyPassword({
            accountAddress,
            password
        });
        const externalServerKeyShares = await this.getExternalServerKeyShares({
            accountAddress,
            password
        });
        return externalServerKeyShares;
    }
    /**
   * Helper function to check if the required wallet fields are present and valid
   * @param accountAddress - The account address of the wallet to check
   * @param walletOperation - The wallet operation that determines required fields
   * @returns boolean indicating if wallet needs to be re-fetched and restored from server
   */ async checkWalletFields({ accountAddress, walletOperation = core$1.WalletOperation.REACH_THRESHOLD, shareCount }) {
        var _existingWallet_externalServerKeyShares;
        let keyshareCheck = false;
        let walletCheck = false;
        let thresholdSignatureSchemeCheck = false;
        let derivationPathCheck = false;
        // check if wallet exists
        const existingWallet = this.walletMap[accountAddress];
        if (existingWallet) {
            walletCheck = true;
        }
        // check if threshold signature scheme exists
        if (existingWallet == null ? void 0 : existingWallet.thresholdSignatureScheme) {
            thresholdSignatureSchemeCheck = true;
        }
        // check if derivation path exists
        if ((existingWallet == null ? void 0 : existingWallet.derivationPath) || (existingWallet == null ? void 0 : existingWallet.derivationPath) === '') {
            derivationPathCheck = true;
        }
        // check if wallet already exists with sufficient keyshares
        if (existingWallet) {
            var _existingWallet_externalServerKeyShares1;
            const { shares } = this.recoverStrategy({
                externalServerKeySharesBackupInfo: existingWallet.externalServerKeySharesBackupInfo || {
                    backups: getExternalServerKeyShareBackupInfo()
                },
                thresholdSignatureScheme: existingWallet.thresholdSignatureScheme,
                walletOperation,
                shareCount
            });
            const { dynamic: requiredDynamicKeyShareIds = [] } = shares;
            const { external: requiredExternalKeyShareIds = [] } = shares;
            // Check if we have enough shares from any backup location
            const totalRequiredShares = requiredDynamicKeyShareIds.length + requiredExternalKeyShareIds.length;
            // Check if we have the required shares either loaded OR available in backup
            const hasLoadedShares = totalRequiredShares <= (((_existingWallet_externalServerKeyShares1 = existingWallet.externalServerKeyShares) == null ? void 0 : _existingWallet_externalServerKeyShares1.length) || 0);
            // Check if backup contains the specific required share IDs
            const hasBackupShares = existingWallet.externalServerKeySharesBackupInfo && (()=>{
                const backupShares = existingWallet.externalServerKeySharesBackupInfo.backups.dynamic;
                const allRequiredIds = [
                    ...requiredDynamicKeyShareIds,
                    ...requiredExternalKeyShareIds
                ];
                return allRequiredIds.every((requiredId)=>backupShares.some((backupShare)=>backupShare.externalKeyShareId === requiredId));
            })();
            if (hasLoadedShares || hasBackupShares) {
                keyshareCheck = true;
            }
        }
        const result = walletCheck && thresholdSignatureSchemeCheck && keyshareCheck && derivationPathCheck;
        this.logger.debug('Wallet checks:', {
            walletCheck,
            thresholdSignatureSchemeCheck,
            keyshareCheck,
            derivationPathCheck,
            existingWallet: !!existingWallet,
            keySharesLength: existingWallet == null ? void 0 : (_existingWallet_externalServerKeyShares = existingWallet.externalServerKeyShares) == null ? void 0 : _existingWallet_externalServerKeyShares.length,
            result
        });
        return result;
    }
    /**
   * verifyPassword attempts to recover and decrypt a single client key share using the provided password.
   * If successful, the key share is encrypted with the new password. This method solely performs the recovery
   * and decryption without storing the restored key shares. If unsuccessful, it throws an error.
   */ async verifyPassword({ accountAddress, password = undefined }) {
        await this.getWallet({
            accountAddress,
            password,
            walletOperation: core$1.WalletOperation.NO_OPERATION
        });
        if (await this.requiresPasswordForOperation({
            accountAddress,
            walletOperation: core$1.WalletOperation.NO_OPERATION
        }) && !password) {
            throw new Error('Password is required for operation but not provided');
        }
        // silent return if no password is provided and operation does not require a password
        if (!password) {
            return;
        }
        const { backups } = await this.getWalletExternalServerKeyShareBackupInfo({
            accountAddress
        });
        const { dynamic: dynamicKeyShareIds = [] } = backups;
        const { external: externalKeyShareIds = [] } = backups;
        // Check if we have any shares available (DYNAMIC or EXTERNAL)
        if (dynamicKeyShareIds.length === 0 && externalKeyShareIds.length === 0) {
            throw new Error('No key shares found');
        }
        try {
            // Recover and store shares to unlock the wallet (storeRecoveredShares defaults to true)
            await this.recoverEncryptedBackupByWallet({
                accountAddress,
                password,
                walletOperation: core$1.WalletOperation.NO_OPERATION
            });
        } catch (error) {
            this.logger.error('Error in verifying password', error);
            throw new Error('Incorrect password');
        }
    }
    async isPasswordEncrypted({ accountAddress }) {
        const externalServerKeySharesBackupInfo = await this.getWalletExternalServerKeyShareBackupInfo({
            accountAddress
        });
        return externalServerKeySharesBackupInfo == null ? void 0 : externalServerKeySharesBackupInfo.passwordEncrypted;
    }
    /**
   * check if the operation requires a password
   */ async requiresPasswordForOperation({ accountAddress, walletOperation = core$1.WalletOperation.REACH_THRESHOLD }) {
        const isEncrypted = await this.isPasswordEncrypted({
            accountAddress
        });
        if (!isEncrypted) {
            return false;
        }
        return this.requiresRestoreBackupSharesForOperation({
            accountAddress,
            walletOperation
        });
    }
    /**
   * check if the operation requires restoring backup shares
   */ async requiresRestoreBackupSharesForOperation({ accountAddress, walletOperation = core$1.WalletOperation.REACH_THRESHOLD }) {
        const externalServerKeySharesBackupInfo = await this.getWalletExternalServerKeyShareBackupInfo({
            accountAddress
        });
        const externalServerKeyShares = this.walletMap[accountAddress].externalServerKeyShares || [];
        if (walletOperation === core$1.WalletOperation.REACH_ALL_PARTIES || walletOperation === core$1.WalletOperation.REFRESH || walletOperation === core$1.WalletOperation.RESHARE) {
            return true;
        }
        const { shares, requiredShareCount } = this.recoverStrategy({
            externalServerKeySharesBackupInfo,
            thresholdSignatureScheme: this.walletMap[accountAddress].thresholdSignatureScheme,
            walletOperation
        });
        const dynamicKeyShareIds = shares[core$1.BackupLocation.DYNAMIC] || [];
        const externalKeyShareIds = shares[core$1.BackupLocation.EXTERNAL] || [];
        // Check if we have enough shares from either location
        const totalAvailableShares = externalServerKeyShares.length + dynamicKeyShareIds.length + externalKeyShareIds.length;
        if (totalAvailableShares >= requiredShareCount) {
            return false;
        }
        return true;
    }
    async getWalletExternalServerKeyShareBackupInfo({ accountAddress }) {
        var _wallet_externalServerKeySharesBackupInfo_backups_BackupLocation_DYNAMIC, _wallet_externalServerKeySharesBackupInfo_backups, _wallet_externalServerKeySharesBackupInfo, _user_verifiedCredentials;
        this.ensureApiClientAuthenticated();
        let wallet = this.walletMap[accountAddress];
        if (!wallet) {
            const fetchedWallet = await this.getWalletByAddress(accountAddress);
            if (!fetchedWallet) {
                throw new Error(`Wallet not found for address 2: ${accountAddress}`);
            }
            wallet = fetchedWallet;
        }
        // Return existing backup info if it exists
        if (((_wallet_externalServerKeySharesBackupInfo = wallet.externalServerKeySharesBackupInfo) == null ? void 0 : (_wallet_externalServerKeySharesBackupInfo_backups = _wallet_externalServerKeySharesBackupInfo.backups) == null ? void 0 : (_wallet_externalServerKeySharesBackupInfo_backups_BackupLocation_DYNAMIC = _wallet_externalServerKeySharesBackupInfo_backups[core$1.BackupLocation.DYNAMIC]) == null ? void 0 : _wallet_externalServerKeySharesBackupInfo_backups_BackupLocation_DYNAMIC.length) > 0) {
            return wallet.externalServerKeySharesBackupInfo;
        }
        // Get backup info from server
        const user = await this.apiClient.getUser(uuid.v4());
        const walletData = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.address.toLowerCase() === accountAddress.toLowerCase());
        return getExternalServerKeyShareBackupInfo({
            walletProperties: walletData == null ? void 0 : walletData.walletProperties
        });
    }
    async getWallet({ accountAddress, walletOperation = core$1.WalletOperation.NO_OPERATION, shareCount = undefined, password = undefined }) {
        try {
            this.ensureApiClientAuthenticated();
            const existingWalletCheck = await this.checkWalletFields({
                accountAddress,
                walletOperation,
                shareCount
            });
            if (existingWalletCheck) {
                this.logger.debug(`Wallet ${accountAddress} already exists`);
                return this.walletMap[accountAddress];
            }
            const wallet = await this.getWalletByAddress(accountAddress);
            if (!wallet) {
                throw new Error(`Wallet not found for address 3: ${accountAddress}`);
            }
            this.logger.debug('Restoring wallet', wallet);
            // The wallet is already processed, so we can use it directly
            this.walletMap[accountAddress] = wallet;
            if (walletOperation !== core$1.WalletOperation.NO_OPERATION && await this.requiresRestoreBackupSharesForOperation({
                accountAddress,
                walletOperation
            })) {
                const decryptedKeyShares = await this.recoverEncryptedBackupByWallet({
                    accountAddress,
                    password: password != null ? password : this.environmentId,
                    walletOperation: walletOperation,
                    shareCount
                });
                this.logger.debug('[DynamicWaasWalletClient] Recovered backup', decryptedKeyShares);
            }
            // externalServerKeyShares
            const walletCount = Object.keys(this.walletMap).length;
            if (walletCount === 0) {
                throw new Error('No wallets found');
            }
            // Return the only wallet if there's just one
            if (walletCount === 1) {
                return Object.values(this.walletMap)[0];
            }
            return this.walletMap[accountAddress];
        } catch (error) {
            this.logger.error('Error in getWallet', error);
            throw error;
        }
    }
    /**
   * Get a single wallet by address
   * First tries the efficient getWaasWalletByAddress endpoint, falls back to getUser() if not available
   */ async getWalletByAddress(accountAddress) {
        // Return cached wallet if available
        if (this.walletMap[accountAddress]) {
            return this.walletMap[accountAddress];
        }
        this.ensureApiClientAuthenticated();
        // Try getting single wallet by address first
        try {
            var _walletResponse_wallet;
            const walletResponse = await this.apiClient.getWaasWalletByAddress({
                walletAddress: accountAddress
            });
            const walletProperties = {
                walletId: walletResponse.wallet.walletId,
                chainName: walletResponse.wallet.chainName,
                accountAddress: walletResponse.wallet.accountAddress,
                externalServerKeyShares: [],
                derivationPath: walletResponse.wallet.derivationPath,
                thresholdSignatureScheme: walletResponse.wallet.thresholdSignatureScheme,
                externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
                    walletProperties: {
                        // @ts-expect-error TODO: update response to get key shares
                        keyShares: ((_walletResponse_wallet = walletResponse.wallet) == null ? void 0 : _walletResponse_wallet.keyShares) || [],
                        thresholdSignatureScheme: walletResponse.wallet.thresholdSignatureScheme,
                        derivationPath: walletResponse.wallet.derivationPath
                    }
                })
            };
            // Cache the wallet
            this.walletMap[accountAddress] = walletProperties;
            return walletProperties;
        } catch (error) {
            var _error_response;
            // If the new endpoint doesn't exist (404 or not implemented), fall back to getUser()
            if ((error == null ? void 0 : (_error_response = error.response) == null ? void 0 : _error_response.status) === 404 || (error == null ? void 0 : error.code) === 'ERR_BAD_REQUEST') {
                var _user_verifiedCredentials, _wallet_walletProperties, _wallet_walletProperties1;
                this.logger.debug('getWaasWalletByAddress endpoint not available, falling back to getUser()');
                // Fallback to getUser() approach
                const user = await this.apiClient.getUser(uuid.v4());
                const wallet = (_user_verifiedCredentials = user.verifiedCredentials) == null ? void 0 : _user_verifiedCredentials.find((vc)=>vc.walletName === 'dynamicwaas' && vc.address.toLowerCase() === accountAddress.toLowerCase());
                if (!wallet) {
                    return null;
                }
                var _wallet_walletProperties_derivationPath;
                const walletProperties = {
                    walletId: wallet.id,
                    chainName: wallet.chain,
                    accountAddress: wallet.address,
                    externalServerKeyShares: [],
                    derivationPath: (_wallet_walletProperties_derivationPath = (_wallet_walletProperties = wallet.walletProperties) == null ? void 0 : _wallet_walletProperties.derivationPath) != null ? _wallet_walletProperties_derivationPath : undefined,
                    thresholdSignatureScheme: (_wallet_walletProperties1 = wallet.walletProperties) == null ? void 0 : _wallet_walletProperties1.thresholdSignatureScheme,
                    externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
                        walletProperties: wallet.walletProperties || {}
                    })
                };
                // Cache the wallet
                this.walletMap[accountAddress] = walletProperties;
                return walletProperties;
            }
            throw error;
        }
    }
    /**
   * Get all wallets (kept for backward compatibility but now uses lazy loading)
   * @deprecated Consider using getWalletByAddress for better performance with large wallet counts
   */ async getWallets() {
        this.logger.warn('getWallets() is deprecated. Use getWalletByAddress() for better performance with large wallet counts.');
        this.ensureApiClientAuthenticated();
        const user = await this.apiClient.getUser(uuid.v4());
        var _user_verifiedCredentials;
        const verifiedCredentials = (_user_verifiedCredentials = user.verifiedCredentials) != null ? _user_verifiedCredentials : [];
        const waasWallets = verifiedCredentials.filter((vc)=>vc.walletName === 'dynamicwaas' && !!vc.address && !!vc.chain);
        const wallets = waasWallets.map((vc)=>{
            var _this_walletMap_vc_address, _vc_walletProperties, _vc_walletProperties1;
            var _vc_walletProperties_thresholdSignatureScheme;
            return {
                walletId: vc.id,
                chainName: core$1.verifiedCredentialNameToChainEnum[vc.chain],
                accountAddress: vc.address,
                externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo({
                    walletProperties: vc.walletProperties
                }),
                externalServerKeyShares: ((_this_walletMap_vc_address = this.walletMap[vc.address]) == null ? void 0 : _this_walletMap_vc_address.externalServerKeyShares) || [],
                derivationPath: (_vc_walletProperties = vc.walletProperties) == null ? void 0 : _vc_walletProperties.derivationPath,
                thresholdSignatureScheme: (_vc_walletProperties_thresholdSignatureScheme = (_vc_walletProperties1 = vc.walletProperties) == null ? void 0 : _vc_walletProperties1.thresholdSignatureScheme) != null ? _vc_walletProperties_thresholdSignatureScheme : core$1.ThresholdSignatureScheme.TWO_OF_TWO
            };
        });
        this.walletMap = wallets.reduce((acc, wallet)=>{
            acc[wallet.accountAddress] = wallet;
            return acc;
        }, {});
        return wallets;
    }
    /**
   * Helper method to initialize or update a wallet entry in the walletMap.
   * This provides a consistent way to set up wallet properties across different operations.
   * @param accountAddress - The account address for the wallet
   * @param walletId - The wallet ID
   * @param chainName - The chain name (e.g., 'BTC', 'EVM')
   * @param thresholdSignatureScheme - The threshold signature scheme
   * @param derivationPath - Optional derivation path for the wallet
   * @param additionalProps - Optional additional properties to merge into the wallet entry
   */ initializeWalletMapEntry({ accountAddress, walletId, chainName, thresholdSignatureScheme, derivationPath, additionalProps = {} }) {
        this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
            accountAddress,
            walletId,
            chainName,
            thresholdSignatureScheme
        }, derivationPath ? {
            derivationPath
        } : {}, {
            externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo()
        }, additionalProps);
        this.logger.debug('walletMap initialized for wallet', {
            context: {
                accountAddress,
                walletId,
                chainName,
                walletMap: this.walletMap
            }
        });
    }
    constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, debug, forwardMPCClient, enableMPCAccelerator = true, logger: logger$1 }){
        this.walletMap = {} // todo: store in session storage
        ;
        this.isApiClientAuthenticated = false;
        this.forwardMPCEnabled = true;
        if (logger$1) {
            this.logger = logger$1;
        } else {
            const defaultLogger = new logger.Logger('DynamicWaasWalletClient');
            defaultLogger.setLogLevel(debug ? 'DEBUG' : 'INFO');
            this.logger = defaultLogger;
        }
        core$1.Logger.configure(this.logger);
        this.environmentId = environmentId;
        this.baseApiUrl = baseApiUrl != null ? baseApiUrl : core$1.DYNAMIC_AUTH_PROD_BASE_API_URL;
        const environment = core$1.getEnvironmentFromUrl(baseApiUrl);
        this.baseMPCRelayApiUrl = baseMPCRelayApiUrl != null ? baseMPCRelayApiUrl : core$1.MPC_RELAY_URL_MAP[environment];
        this.debug = Boolean(debug);
        this.forwardMPCEnabled = enableMPCAccelerator || Boolean(forwardMPCClient);
        this.resolvedForwardMPCClient = forwardMPCClient != null ? forwardMPCClient : (()=>{
            if (!this.forwardMPCEnabled) return undefined;
            const environment = core$1.getEnvironmentFromUrl(baseApiUrl);
            const enclaveUrl = core$1.DYNAMIC_FORWARD_MPC_ENCLAVE_URL_MAP[environment];
            if (!enclaveUrl) throw new Error(`No ForwardMPC enclave URL configured for environment: ${environment}`);
            return new forwardMpcClient.ForwardMPCClientV2(enclaveUrl, {
                reconnectInterval: 5000,
                reconnectAttempts: 5,
                connectionTimeout: 10000,
                attestationConfig: core$1.DYNAMIC_FORWARD_MPC_ENCLAVE_ATTESTATION_CONFIG_MAP[environment],
                logger: this.logger
            });
        })();
        // Initialize API client with forwardMPCClient
        this.apiClient = new core$1.DynamicApiClient({
            environmentId,
            baseApiUrl,
            forwardMPCClient: this.resolvedForwardMPCClient,
            logger: this.logger
        });
    }
}

const createCore = ({ environmentId, baseApiUrl, baseMPCRelayApiUrl, debug = false, logger: logger$1 })=>{
    let coreLogger;
    if (logger$1) {
        coreLogger = logger$1;
    } else {
        const defaultLogger = new logger.Logger('DynamicWaasWalletClient');
        defaultLogger.setLogLevel(debug ? 'DEBUG' : 'INFO');
        coreLogger = defaultLogger;
    }
    core$1.Logger.configure(coreLogger);
    const createApiClient = (options = {})=>{
        return new core$1.DynamicApiClient(_extends({
            environmentId,
            baseApiUrl
        }, options, {
            logger: coreLogger
        }));
    };
    return {
        environmentId,
        createApiClient,
        logger: coreLogger,
        baseMPCRelayApiUrl,
        baseApiUrl,
        debug
    };
};

// Helper function to create API client for delegated operations
const createDelegatedApiClient = (client, options = {})=>{
    return client.createApiClient(options);
};
// Helper function to create API client with wallet-specific headers
const createDelegatedApiClientWithWalletKey = (client, walletApiKey)=>{
    const apiClient = client.createApiClient();
    // Add the wallet-specific API key header to all requests from this client
    apiClient.apiClient.defaults.headers['x-dyn-wallet-api-key'] = walletApiKey;
    return apiClient;
};
const createDelegatedWalletClient = ({ environmentId, baseApiUrl, baseMPCRelayApiUrl, apiKey, debug = false })=>{
    const core = createCore({
        environmentId,
        baseApiUrl,
        baseMPCRelayApiUrl,
        debug
    });
    // Store the API key for use in delegated operations
    core.apiKey = apiKey;
    const walletMap = {};
    const client = {
        get environmentId () {
            return core.environmentId;
        },
        get debug () {
            return core.debug;
        },
        get apiUrl () {
            var _core_baseApiUrl;
            return (_core_baseApiUrl = core.baseApiUrl) != null ? _core_baseApiUrl : 'https://app.dynamicauth.com';
        },
        get wallets () {
            return walletMap;
        },
        createApiClient: (options = {})=>{
            return core.createApiClient(_extends({
                authToken: apiKey
            }, options));
        },
        logger: core.logger,
        apiKey,
        baseMPCRelayApiUrl: core.baseMPCRelayApiUrl
    };
    return client;
};

const dynamicDelegatedSign = async (client, { walletId, message, isFormatted, walletApiKey, onError, context })=>{
    const dynamicRequestId = uuid.v4();
    // Convert message to hex if it's a Uint8Array
    if (typeof message !== 'string') {
        message = '0x' + Buffer.from(message).toString('hex');
    }
    const apiClient = createDelegatedApiClientWithWalletKey(client, walletApiKey);
    const data = await apiClient.delegatedSignMessage({
        walletId,
        message,
        isFormatted,
        dynamicRequestId,
        onError,
        context: context ? JSON.parse(JSON.stringify(context, (_key, value)=>typeof value === 'bigint' ? value.toString() : value)) : undefined
    });
    return data;
};
const delegatedSign = async (client, { chainName, message, roomId, keyShare, derivationPath, isFormatted })=>{
    try {
        const mpcSigner = getMPCSigner({
            chainName,
            baseRelayUrl: client.baseMPCRelayApiUrl
        });
        const formattedMessage = isFormatted ? new node.MessageHash(message) : formatMessage(chainName, message);
        const signature = await mpcSigner.sign(roomId, keyShare, formattedMessage, derivationPath);
        return signature;
    } catch (error) {
        client.logger.error('Error in delegatedSign', error);
        throw error;
    }
};
const delegatedSignMessage = async (client, { walletId, walletApiKey, keyShare, message, chainName, isFormatted = false, onError, context })=>{
    // Validate required parameters
    if (!keyShare) {
        throw new Error('Delegated key share is required to sign a message');
    }
    const wallet = await getWallet(client, {
        walletId
    });
    // Perform the dynamic server sign
    const data = await dynamicDelegatedSign(client, {
        walletId,
        walletApiKey,
        message,
        isFormatted,
        onError,
        context
    });
    const derivationPath = wallet.derivationPath && wallet.derivationPath !== '' ? new Uint32Array(Object.values(JSON.parse(wallet.derivationPath))) : undefined;
    // Perform the external server sign and return the signature
    const signature = await delegatedSign(client, {
        chainName,
        message,
        roomId: data.roomId,
        keyShare,
        derivationPath,
        isFormatted
    });
    return signature;
};
// Helper function to get wallet (to be implemented in wallet module)
const getWallet = async (client, { walletId })=>{
    const wallets = client.wallets;
    // Check if wallet is already cached
    if (wallets[walletId]) {
        return wallets[walletId];
    }
    // Fetch wallet from API
    const apiClient = createDelegatedApiClient(client);
    const { wallet } = await apiClient.getWaasWalletById({
        walletId
    });
    const waasWallet = {
        walletId,
        chainName: wallet.chainName,
        accountAddress: wallet.accountAddress,
        externalServerKeyShares: [],
        derivationPath: wallet.derivationPath,
        thresholdSignatureScheme: wallet.thresholdSignatureScheme,
        externalServerKeySharesBackupInfo: {
            passwordEncrypted: false,
            backups: {
                dynamic: [],
                googleDrive: [],
                iCloud: [],
                user: [],
                external: [],
                delegated: []
            }
        }
    };
    // Cache the wallet
    wallets[walletId] = waasWallet;
    return waasWallet;
};

const revokeDelegation = async (client, walletId)=>{
    try {
        // TODO: Uncomment when API method is implemented
        // const apiClient = createDelegatedApiClient(client);
        // await apiClient.revokeDelegation({
        //   walletId,
        // });
        client.logger.info(`Delegation revoked for wallet: ${walletId}`);
    } catch (error) {
        client.logger.error('Error revoking delegation', error);
        throw new Error('Failed to revoke delegation');
    }
};

Object.defineProperty(exports, "SOLANA_RPC_URL", {
  enumerable: true,
  get: function () { return core$1.SOLANA_RPC_URL; }
});
Object.defineProperty(exports, "ThresholdSignatureScheme", {
  enumerable: true,
  get: function () { return core$1.ThresholdSignatureScheme; }
});
Object.defineProperty(exports, "WalletOperation", {
  enumerable: true,
  get: function () { return core$1.WalletOperation; }
});
Object.defineProperty(exports, "getMPCChainConfig", {
  enumerable: true,
  get: function () { return core$1.getMPCChainConfig; }
});
exports.DynamicWalletClient = DynamicWalletClient;
exports.base64ToBytes = base64ToBytes;
exports.bytesToBase64 = bytesToBase64;
exports.createDelegatedWalletClient = createDelegatedWalletClient;
exports.createLogError = createLogError;
exports.delegatedSignMessage = delegatedSignMessage;
exports.ensureBase64Padding = ensureBase64Padding;
exports.formatEvmMessage = formatEvmMessage;
exports.formatMessage = formatMessage;
exports.getExternalServerKeyShareBackupInfo = getExternalServerKeyShareBackupInfo;
exports.getMPCSignatureScheme = getMPCSignatureScheme;
exports.getMPCSigner = getMPCSigner;
exports.isHexString = isHexString;
exports.logError = logError;
exports.mergeUniqueKeyShares = mergeUniqueKeyShares;
exports.retryPromise = retryPromise;
exports.revokeDelegation = revokeDelegation;
exports.stringToBytes = stringToBytes;
Object.keys(core).forEach(function (k) {
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
    enumerable: true,
    get: function () { return core[k]; }
  });
});
