Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
c88ac55
feat: :green_heart: added gitlab ci
a0ngo Jun 3, 2025
b69f244
Merge branch 'update-ci' into 'main'
Jun 3, 2025
d68e656
fix: fixed gitlab ci
a0ngo Jun 3, 2025
9b96863
test: new-version label test
a0ngo Jun 3, 2025
66f01e0
Merge branch 'test-ci' into 'main'
Jun 3, 2025
e18921a
fix: :lock: updated encryption of generated rsa key
a0ngo Jun 4, 2025
4bdf952
Merge Hidden branch into Main
tomer-shoham Sep 18, 2025
3fed138
Merge branch 'hidden' into 'main'
SlavaSereb Sep 18, 2025
5726581
feat: add support for XLM wallet operations and enhance account handling
tomer-shoham Sep 28, 2025
d0a18c6
feat: add support for additional Ethereum testnets and basechain assets
tomer-shoham Sep 28, 2025
a0873d5
chore: bump version numbers
tomer-shoham Sep 28, 2025
1a72a86
feat: add support for XRP wallet operations and enhance asset handling
tomer-shoham Sep 29, 2025
3809e07
fix: update Ethereum Sepolia testnet RPC URL
tomer-shoham Sep 30, 2025
e31d104
chore: update version to 1.8.2 in package.json
tomer-shoham Sep 30, 2025
d27bc73
feat: add API key support for blockchair based assets
tomer-shoham Oct 8, 2025
a09c4e0
feat: integrate API key handling
tomer-shoham Oct 8, 2025
8ea42d9
feat: enhance BTC wallet utils with API key support and refactor methods
tomer-shoham Oct 8, 2025
aa4b525
fix: update the context state immediately
tomer-shoham Oct 8, 2025
be78619
feat: add support for broadcasting transactions via Blockstream on Bi…
tomer-shoham Oct 8, 2025
821a05a
chore: update package version to 1.8.2
tomer-shoham Oct 8, 2025
ec54647
feat: enhance transaction broadcasting with asset ID support and logg…
tomer-shoham Oct 8, 2025
dcdeade
Merge branch 'feat/btc-api-key' into 'main'
SlavaSereb Oct 8, 2025
3033891
fix: blockchair API rate limits
SlavaSereb Oct 12, 2025
3df71ec
chore: update comments
SlavaSereb Oct 12, 2025
8fd3db2
fix: correct AVAX and AVAXTEST RPC URLs for Avalanche C-Chain and Tes…
tomer-shoham Nov 17, 2025
b24a127
chore: update package version to 1.8.3
tomer-shoham Nov 17, 2025
0ff0af8
chore: update app version
tomer-shoham Dec 2, 2025
a15c1ba
fix: support for xrp explorer url
tomer-shoham Dec 2, 2025
185d45e
feat: query reserve requirements dynamically from network
tomer-shoham Dec 2, 2025
09e54e7
Merge branch 'fix/missing-evm-keys' into 'main'
SlavaSereb Feb 17, 2026
3b5bb15
Merge branch 'fix/btc-api-key' into 'main'
SlavaSereb Feb 17, 2026
512bf8f
Merge branch 'fix/avax-rpcs' into 'main'
SlavaSereb Feb 17, 2026
e60b62d
Merge branch 'main' into 'fix/xrp-dynamic-reserves'
SlavaSereb Feb 17, 2026
457c80f
Merge branch 'fix/xrp-dynamic-reserves' into 'main'
SlavaSereb Feb 17, 2026
dae8799
remove e2e flag fow showing QR URL
SlavaSereb Feb 17, 2026
b9945cb
set version to 1.8.3
SlavaSereb Feb 17, 2026
37f3133
fix versions
SlavaSereb Feb 17, 2026
2d82f7c
Merge branch 'feat/show-qr-url-prod' into 'main'
SlavaSereb Feb 19, 2026
cafd4b4
feat: bump version to 1.8.4
tomer-shoham Apr 20, 2026
d0f0e59
feat: implement v2 decryption for mobile key sharing and update types
tomer-shoham Apr 20, 2026
92451ce
feat: add optional logging for mobile key share decryption and recove…
tomer-shoham May 27, 2026
64e54f9
Update CODEOWNERS
SlavaSereb Jun 1, 2026
fe06281
Merge branch 'chore/change-codeowners' into 'main'
SlavaSereb Jun 1, 2026
cc44ebd
Merge branch 'feat/mobile-key-share-v2' into 'main'
SlavaSereb Jun 1, 2026
73b8ed0
Implement feature X to enhance user experience and fix bug Y in module Z
tomer-shoham Aug 5, 2026
0fba10a
fix: update derivation key handling for wallet addresses
tomer-shoham Aug 5, 2026
04bd113
fix: ensure y-coordinate padding for decompressed public key in Tron …
tomer-shoham Aug 5, 2026
7ade24b
fix: bump version to 1.8.5 for recovery-utility and recovery-relay
tomer-shoham Aug 5, 2026
ac5e649
Merge branch 'fix/tron-address-y-coordinate-padding' into 'main'
SlavaSereb Aug 5, 2026
8d691cc
feat: fix NCW recovery and add EdDSA wallet share derivation
goweiss Aug 6, 2026
1588010
feat: update version to 1.8.6
tomer-shoham Aug 11, 2026
05592e9
Merge branch 'main' into 'feat/ncw-recovery-fix-and-eddsa-support'
tomer-shoham Aug 11, 2026
21399fc
Merge branch 'feat/ncw-recovery-fix-and-eddsa-support' into 'main'
goweiss Aug 12, 2026
8823657
chore: remove download links from README for macOS/Linux
tomer-shoham Sep 23, 2026
6a09be8
refactor: remove yarn.lock
tomer-shoham Sep 23, 2026
2d2917f
chore: reconcile GitHub history (GitLab is source of truth)
tomer-shoham Sep 23, 2026
e22aba0
chore: remove GitLab CI config from public repo
tomer-shoham Sep 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@
*.pem
*.key

# Claude
.claude/
CLAUDE.md

# Dependencies
dependencies
node_modules
.pnp
.pnp.js
.claude/
yarn.lock
# Generated dependency attributions
ATTRIBUTION.md
.gitlab-ci.yml

# Testing
coverage
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
Recover Fireblocks assets and keys in a disaster, verify a Recovery Kit, or generate keys to set up a new Recovery Kit.
<br />
<br />
<br />
<a href="#" target="_blank">
<img src="docs/img/splash.png" alt="Screenshot" />
</a>
Expand All @@ -18,7 +17,7 @@

## 🆕 Coming from [fireblocks-key-recovery-tool](https://github.com/fireblocks/fireblocks-key-recovery-tool)?

[Recovery Utility](apps/recovery-utility) offers a UI for your entire workspace backup and recovery lifecycle.
[Recovery Utility](apps/recovery-utility) offers a simple UI for your entire workspace backup and recovery lifecycle.

- Generate and verify keys for a new Recovery Kit.
- Verify your recovery procedure (sanity test).
Expand Down
2 changes: 1 addition & 1 deletion apps/recovery-relay/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"author": "Fireblocks (https://www.fireblocks.com)",
"repository": "https://github.com/fireblocks/recovery/tree/main/apps/recovery-relay",
"license": "GPL-3.0-or-later",
"version": "1.8.4",
"version": "1.8.6",
"private": true,
"scripts": {
"dev": "next dev",
Expand Down
9 changes: 2 additions & 7 deletions apps/recovery-utility/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@
Recover Fireblocks assets and keys in a disaster, verify a Recovery Kit, or generate keys to set up a new Recovery Kit.
<br />
<br />
<a href="https://github.com/fireblocks/recovery/releases">
⬇️ Download for macOS / Linux
</a>
<br />
<br />
<a href="#" target="_blank">
<img src="../../docs/img/splash.png" alt="Screenshot" />
</a>
Expand All @@ -28,8 +23,8 @@
- Protected with a very strong password
- Encrypted on all partitions
- Stored in a safe box when not in use
2. [Install the latest release of Recovery Utility](https://github.com/fireblocks/recovery/releases) on the offline recovery machine.
3. **(Optional)** [Install the latest release of Recovery Relay](https://github.com/fireblocks/recovery/releases) on a web server. [Recovery Relay](../recovery-relay/) is a companion web app that gets wallet balances and sends transactions without revealing your private keys.
2. Install the latest release of Recovery Utility on the offline recovery machine.
3. **(Optional)** Install the latest release of Recovery Relay on a web server. [Recovery Relay](../recovery-relay/) is a companion web app that gets wallet balances and sends transactions without revealing your private keys.
4. Open Recovery Utility to use one of the following tools...

### 🧰 Tools
Expand Down
2 changes: 1 addition & 1 deletion apps/recovery-utility/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"author": "Fireblocks (https://www.fireblocks.com)",
"repository": "https://github.com/fireblocks/recovery/tree/main/apps/recovery-utility",
"homepage": "https://www.fireblocks.com",
"version": "1.8.3",
"version": "1.8.6",
"license": "GPL-3.0-or-later",
"private": true,
"main": "app/background.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,11 @@ export const RecoveryForm = ({ verifyOnly }: Props) => {
const maskedExtendedKeys: UtilityExtendedKeys = {};

Object.entries(recoveredKeys).forEach(([keysetId, value]) => {
if (keysetId === 'ncwMaster' && !verifyOnly) {
maskedExtendedKeys.ncwMaster = value as WalletMaster | undefined;
// recoverKeys returns the NCW master under `ncwWalletMaster`, not as a keyset entry
if (keysetId === 'ncwWalletMaster') {
if (!verifyOnly) {
maskedExtendedKeys.ncwMaster = value as WalletMaster | undefined;
}
return;
}

Expand Down
6 changes: 5 additions & 1 deletion apps/recovery-utility/renderer/lib/recoverExtendedKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ export const recoverExtendedKeys = async (args: Args) => {
} as KeyRecoveryConfig;
}

config = { ...config, recoverOnlyNCW: args.recoverOnlyNCW };
config = {
...config,
recoverOnlyNCW: args.recoverOnlyNCW,
onLog: (msg: string) => logger.info(msg),
};

const response = recoverKeys(config);
return response;
Expand Down
13 changes: 12 additions & 1 deletion apps/recovery-utility/renderer/pages/ncw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,18 @@ const NCW = () => {

const walletId = data['Wallet Id'];
try {
setDerivedWalletKeys((prev) => ({ ...prev, [walletId]: euWallet.derivePrivateKey(walletId, 'MPC_ECDSA_SECP256K1') }));
const ecdsa = euWallet.derivePrivateKey(walletId, 'MPC_ECDSA_SECP256K1');
const eddsa = euWallet.derivePrivateKey(walletId, 'MPC_EDDSA_ED25519');

const mergedShares = ecdsa.shares.map((ecdsaShare) => {
const eddsaShare = eddsa.shares.find((s) => s.cosigner === ecdsaShare.cosigner);
return { ...ecdsaShare, ...eddsaShare };
});

setDerivedWalletKeys((prev) => ({
...prev,
[walletId]: { chainCode: ecdsa.chainCode, shares: mergedShares },
}));
} catch (e) {
logger.error('Failed to derive wallet for wallet id:', walletId, e);
throw e;
Expand Down
10 changes: 5 additions & 5 deletions docs/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
* @fireblocks-solutions-engineering

# Recovery Utility
packages/recovery-utility/ @fireblocks-solutions-engineering @Burry @gburry-fireblocks
packages/recovery-utility/ @fireblocks-solutions-engineering @slava23 @nadav14 @costyb

# Recovery Relay
packages/recovery-relay/ @fireblocks-solutions-engineering @Burry @gburry-fireblocks
packages/recovery-relay/ @fireblocks-solutions-engineering @slava23 @nadav14 @costyb

# Shared frontend components and utilities
packages/shared/ @fireblocks-solutions-engineering @Burry @gburry-fireblocks
packages/shared/ @fireblocks-solutions-engineering @slava23 @nadav14 @costyb

# Extended Key Recovery module
packages/extended-key-recovery/ @fireblocks-solutions-engineering @agoltzman
packages/extended-key-recovery/ @fireblocks-solutions-engineering @slava23 @nadav14 @costyb

# Wallet Derivation helpers
packages/wallet-derivation/ @fireblocks-solutions-engineering @Burry @gburry-fireblocks
packages/wallet-derivation/ @fireblocks-solutions-engineering @slava23 @nadav14 @costyb
15 changes: 15 additions & 0 deletions packages/extended-key-recovery/src/decrypt.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as forge from 'node-forge';
import { pbkdf2Sync, createDecipheriv } from 'crypto';

const _unpad = (text: Buffer, k = 16): Buffer => {
const nl = text.length;
Expand All @@ -13,6 +14,20 @@ const _unpad = (text: Buffer, k = 16): Buffer => {
return text.subarray(0, l_idx);
};

export const decryptMobilePrivateKeyV2 = (
pass: string,
userId: string,
encryptedKey: Buffer,
iv: string,
kdfHash: string,
kdfIterations: number,
): Buffer => {
const digest = kdfHash.toUpperCase() === 'SHA256' ? 'sha256' : 'sha1';
const wrappedKey = pbkdf2Sync(pass, userId, kdfIterations, 32, digest);
const decipher = createDecipheriv('aes-256-cbc', wrappedKey, Buffer.from(iv, 'hex'));
return Buffer.concat([decipher.update(encryptedKey), decipher.final()]);
};

export const decryptMobilePrivateKey = (pass: string, userId: string, encryptedKey: Buffer): Buffer => {
const wrappedKey = forge.pkcs5.pbkdf2(pass, userId, 10000, 32, 'sha1');
const decipher = forge.cipher.createDecipher(
Expand Down
19 changes: 17 additions & 2 deletions packages/extended-key-recovery/src/mobileKey.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { decryptMobilePrivateKey } from './decrypt';
import { decryptMobilePrivateKey, decryptMobilePrivateKeyV2 } from './decrypt';
import { getPlayerId } from './players';
import { DecryptMobileKeyError, KeyIdNotInMetadata, MobileKeyShare, SigningKeyMetadata, UnknownAlgorithmError } from './types';

Expand All @@ -13,6 +13,7 @@ export const recoverMobileKeyShare = (
signingKeys: { [key: string]: SigningKeyMetadata },
keyShareStr: string,
mobilePass: string,
onLog?: (message: string) => void,
) => {
const keyShare = JSON.parse(keyShareStr) as MobileKeyShare;
const { keyId } = keyShare;
Expand All @@ -22,7 +23,21 @@ export const recoverMobileKeyShare = (
}

try {
decryptedKey = decryptMobilePrivateKey(mobilePass, keyShare.userId, Buffer.from(keyShare.encryptedKey, 'hex'));
const meta = keyShare.encryptionMetaData;
if (meta?.version === 2 && meta.iv && meta.kdfHash && meta.kdfIterations) {
onLog?.(`[mobileKey] Decrypting share with V2 (kdfHash=${meta.kdfHash}, kdfIterations=${meta.kdfIterations})`);
decryptedKey = decryptMobilePrivateKeyV2(
mobilePass,
keyShare.userId,
Buffer.from(keyShare.encryptedKey, 'hex'),
meta.iv,
meta.kdfHash,
meta.kdfIterations,
);
} else {
onLog?.(`[mobileKey] Decrypting share with V1 (metaVersion=${meta?.version ?? 'none'})`);
decryptedKey = decryptMobilePrivateKey(mobilePass, keyShare.userId, Buffer.from(keyShare.encryptedKey, 'hex'));
}
} catch (e) {
throw new DecryptMobileKeyError();
}
Expand Down
5 changes: 3 additions & 2 deletions packages/extended-key-recovery/src/recover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ const recoverKeysShares = (
mobilePass: string,
rsaFileData: string,
rsaPass: string,
onLog?: (message: string) => void,
): PlayerData => {
const players: PlayerData = {};
for (const file of zipFiles) {
if (file.entryName.startsWith('MOBILE')) {
const { keyId, playerId, value } = recoverMobileKeyShare(signingKeys, file.getData().toString(), mobilePass);
const { keyId, playerId, value } = recoverMobileKeyShare(signingKeys, file.getData().toString(), mobilePass, onLog);

@semgrep-code-fireblocks semgrep-code-fireblocks Bot Sep 23, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Risk: Affected versions of adm-zip are vulnerable to Memory Allocation with Excessive Size Value. adm-zip allocates a ZIP entry's output buffer with Buffer.alloc() sized from the uncompressed size declared in the archive's central directory, before validating that value against the data actually present. Reading, testing, or extracting a crafted archive via readFile(), readFileAsync(), readAsText(), readAsTextAsync(), extractEntryTo(), extractAllTo(), extractAllToAsync(), test(), or a per-entry getData()/getDataAsync() therefore commits the attacker-declared allocation before any CRC or size check runs. A 105-byte ZIP with a single stored entry declaring a size of 1,774,399,200 commits roughly 1.8 GB of resident memory — about 16 million times the input size — which can exhaust process memory and deny service, and will OOM-kill the process outright on memory-constrained hosts such as containers or serverless runtimes.

Fix: Upgrade this library to at least version 0.6.1 at recovery/yarn.lock:5131.

Reference(s): https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-83170, GHSA-7q85-xj36-vmfc

🌟 Fixed in commit 6a09be8 🌟

@semgrep-code-fireblocks semgrep-code-fireblocks Bot Sep 23, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Risk: Affected versions of adm-zip are vulnerable to Memory Allocation with Excessive Size Value / Uncontrolled Resource Consumption. adm-zip allocates a decompression buffer sized directly from the untrusted uncompressed-size field in a ZIP entry header without validating it against the actual compressed data. When reading, testing, or extracting a crafted archive via readFile(), readAsText(), readAsTextAsync(), extractEntryTo(), extractAllTo(), extractAllToAsync(), test(), or a per-entry getData(), a tiny (~120-byte) ZIP declaring a multi-gigabyte uncompressed size forces an enormous Buffer.alloc, exhausting process memory and causing a denial of service.

Fix: Upgrade this library to at least version 0.6.0 at recovery/yarn.lock:5131.

Reference(s): https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-42960, GHSA-xcpc-8h2w-3j85, CVE-2026-39244

🍰 Fixed in commit 6a09be8 🍰

if (players[keyId] === undefined) {
players[keyId] = {};
}
Expand Down Expand Up @@ -174,7 +175,7 @@ export const recoverKeys = (params: KeyRecoveryConfig): RecoveredKeys => {
return { ncwWalletMaster: walletMaster };
}

const players: PlayerData = recoverKeysShares(zipFiles, signingKeys, mobilePass, rsaFileData, params.rsaPass);
const players: PlayerData = recoverKeysShares(zipFiles, signingKeys, mobilePass, rsaFileData, params.rsaPass, params.onLog);

for (const keyId in signingKeys) {
if (!Object.keys(players).includes(keyId)) {
Expand Down
14 changes: 14 additions & 0 deletions packages/extended-key-recovery/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,20 @@ export class InvalidMasterKey extends Error {

export type PlayerData = { [keyId: string]: { [playerId: string]: bigint } };

export type MobileKeyShareEncryptionMetaData = {
iv?: string;
kdfHash?: string;
kdfIterations?: number;
version?: number;
};

export type MobileKeyShare = {
encryptedKey: string;
keyId: string;
deviceId: string;
userId: string;
encryptionAlgorithm: string;
encryptionMetaData?: MobileKeyShareEncryptionMetaData;
};

export type RecoveredKey = {
Expand Down Expand Up @@ -178,6 +186,12 @@ export type KeyRecoveryConfig = {
* Should only recover NCW wallet
*/
recoverOnlyNCW: boolean;

/**
* Optional logger callback. Used to surface non-sensitive flow info
* (e.g. v1 vs v2 mobile-key decryption dispatch) to the host app's logger.
*/
onLog?: (message: string) => void;
} & (
| {
/**
Expand Down
12 changes: 7 additions & 5 deletions packages/shared/hooks/useBaseWorkspace/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,7 @@ export const useBaseWorkspace = <App extends 'utility' | 'relay', Derivation ext
if (app === 'utility') {
const keys = extendedKeys as UtilityExtendedKeys;
const newExtendedKeys: KeysetMap = { ...prev.extendedKeys };
const newWorkspace = {
...prev,
ncwMaster: keys.ncwMaster,
};
const newWorkspace = { ...prev };
Object.entries(keys).forEach(([keysetId, value]) => {
if (keysetId === 'ncwMaster') {
return;
Expand All @@ -131,7 +128,12 @@ export const useBaseWorkspace = <App extends 'utility' | 'relay', Derivation ext
};
});

newWorkspace.extendedKeys = { ...newExtendedKeys };
// ncwMaster lives alongside the keyset entries on extendedKeys - every consumer
// (Layout, /ncw, wallet derivation) reads it from there.
newWorkspace.extendedKeys = {
...newExtendedKeys,
ncwMaster: keys.ncwMaster ?? (newExtendedKeys as UtilityExtendedKeys).ncwMaster,
} as typeof newWorkspace.extendedKeys;

return newWorkspace;
}
Expand Down
7 changes: 4 additions & 3 deletions packages/shared/hooks/useBaseWorkspace/reduceDerivations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const reduceDerivations = <App extends 'utility' | 'relay', T extends Bas

// Mock derivation
if (address) {
wallet.derivations.set(address, {
wallet.derivations.set(getDerivationMapKey(assetId, address), {
assetId,
path,
pathParts: [44, path.coinType, path.account, path.changeIndex, path.addressIndex],
Expand Down Expand Up @@ -159,7 +159,8 @@ export const reduceDerivations = <App extends 'utility' | 'relay', T extends Bas

const missingWalletKey = (hasXpub && !publicKey) || (hasXprv && !privateKey);

const shouldDerive = canDerive && (missingWalletKey || !address || !wallet.derivations.has(address));
const shouldDerive =
canDerive && (missingWalletKey || !address || !wallet.derivations.has(getDerivationMapKey(assetId, address)));

// Derive wallet
if (shouldDerive) {
Expand All @@ -169,7 +170,7 @@ export const reduceDerivations = <App extends 'utility' | 'relay', T extends Bas
if (address && derivation.address !== address) {
// TODO: Show notice in UI when this happens. For now just remove the erroneous imported address
logger.warn(`Address mismatch, dropping import. Imported ${address}, derived ${derivation.address}`);
wallet.derivations.delete(address);
wallet.derivations.delete(getDerivationMapKey(assetId, address));
}

wallet.derivations.set(getDerivationMapKey(derivation.assetId, derivation.address), derivation);
Expand Down
2 changes: 1 addition & 1 deletion packages/wallet-derivation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export type KeyDerivation = Readonly<{

export type NCWalletShare = {
chainCode: string;
shares: { cosigner: string; MPC_CMP_ECDSA_SECP256K1: string }[];
shares: { cosigner: string; MPC_CMP_ECDSA_SECP256K1?: string; MPC_CMP_EDDSA_ED25519?: string }[];
};

export interface Derivation {
Expand Down
Loading