{"id":45949986,"url":"https://github.com/fystack/mpcium-client-ts","last_synced_at":"2026-02-28T12:16:05.902Z","repository":{"id":291139641,"uuid":"976716110","full_name":"fystack/mpcium-client-ts","owner":"fystack","description":"Mpcium client implementation in Typescript","archived":false,"fork":false,"pushed_at":"2025-07-30T14:04:31.000Z","size":7396,"stargazers_count":3,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-30T16:44:52.235Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fystack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-02T16:04:02.000Z","updated_at":"2025-07-30T14:04:36.000Z","dependencies_parsed_at":"2025-07-30T16:05:48.740Z","dependency_job_id":"321b54dd-a346-41fb-b686-4f01ed936ae7","html_url":"https://github.com/fystack/mpcium-client-ts","commit_stats":null,"previous_names":["fystack/mpcium-client-ts"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fystack/mpcium-client-ts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fystack%2Fmpcium-client-ts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fystack%2Fmpcium-client-ts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fystack%2Fmpcium-client-ts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fystack%2Fmpcium-client-ts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fystack","download_url":"https://codeload.github.com/fystack/mpcium-client-ts/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fystack%2Fmpcium-client-ts/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29933338,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-28T09:58:13.507Z","status":"ssl_error","status_checked_at":"2026-02-28T09:57:57.047Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-28T12:16:04.921Z","updated_at":"2026-02-28T12:16:05.876Z","avatar_url":"https://github.com/fystack.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mpcium TypeScript Client\n\nA TypeScript client for interacting with Mpcium Multi-Party Computation (MPC) service to generate and manage wallets and sign transactions across multiple blockchains.\n\n### Client sign\n\n![alt text](./images/sign-solana.png)\n\n### MPCIUM nodes coordinate to sign transaction\n\n![alt text](./images/mpc-nodes.png)\n\n## Prerequisites\n\nImportant: Before using this TypeScript client, you need to set up the Mpcium MPC nodes. The nodes provide the underlying MPC infrastructure that this client connects to.\nPlease follow the installation and setup instructions at [mpcium](https://github.com/fystack/mpcium) to deploy the required MPC nodes. Typically, you'll need to run multiple nodes (e.g., 3 nodes in a 2-of-3 threshold setup) before using this client.\n\n```sh\n# Example of starting MPC nodes (after installing from the repository)\nmpcium start -n node0\nmpcium start -n node1\nmpcium start -n node2\n```\n\n## Overview\n\nMpcium is a service that provides secure key management and transaction signing using Multi-Party Computation. This client library allows you to:\n\n- Generate cryptographic keys without exposing private key material\n- Sign transactions for multiple blockchain networks\n- Receive cryptographic operation results through event subscriptions\n\n## Supported Key Types and Blockchains\n\n- **ECDSA**: Bitcoin, Ethereum, and other EVM-compatible chains\n- **EdDSA**: Solana, Polkadot, Cardano, and other EdDSA-based chains\n\n## Installation\n\n```bash\nnpm install @fystack/mpcium-ts\n```\n\n## Creating a client\n\n- User need to generate `event_initiator.key` through [mpcium-cli](https://github.com/fystack/mpcium/blob/master/INSTALLATION.md) before using this client\n\n```ts\nimport { connect } from \"nats\";\nimport { MpciumClient } from \"@fystack/mpcium-ts\";\n\nasync function setupClient() {\n  // First, establish NATS connection\n  const nc = await connect({ servers: \"nats://localhost:4222\" });\n\n  // Create client with key path\n  const mpcClient = await MpciumClient.create({\n    nc: nc,\n    keyPath: \"./event_initiator.key\",\n  });\n\n  return mpcClient;\n}\n```\n\n### Encrypted client (Recommended for production usage)\n\n```ts\nconst mpcClient = await MpciumClient.create({\n  nc: nc,\n  keyPath: \"./event_initiator.key.age\",\n  password: \"your-secure-password\", // Stored and load secure vault like KMS, Hashicorp vault\n});\n```\n\n### Generating a Wallet\n\n```ts\nimport { connect } from \"nats\";\nimport { MpciumClient } from \"@fystack/mpcium-ts\";\nimport fs from \"fs\";\n\nasync function generateWallet() {\n  const nc = await connect({ servers: \"nats://localhost:4222\" });\n  const mpcClient = await MpciumClient.create({\n    nc: nc,\n    keyPath: \"./event_initiator.key\",\n  });\n\n  // Store wallets in a file (for testing only)\n  const walletsFile = \"./examples/wallets.json\";\n  const wallets = fs.existsSync(walletsFile)\n    ? JSON.parse(fs.readFileSync(walletsFile, \"utf8\"))\n    : {};\n\n  // Subscribe to wallet creation results\n  mpcClient.onWalletCreationResult((event) =\u003e {\n    console.log(\"Received wallet creation result:\", event);\n\n    // Store wallet info with wallet_id as key\n    wallets[event.wallet_id] = {\n      wallet_id: event.wallet_id,\n      ecdsa_pub_key: event.ecdsa_pub_key,\n      eddsa_pub_key: event.eddsa_pub_key,\n    };\n\n    // Save to file (in production, use a database)\n    fs.writeFileSync(walletsFile, JSON.stringify(wallets, null, 2));\n    console.log(`Wallet ${event.wallet_id} saved to wallets.json`);\n    console.log(\n      \"NOTE: File storage is for testing only. Use a database in production.\"\n    );\n  });\n\n  // Create the wallet\n  const walletID = await mpcClient.createWallet();\n  console.log(`CreateWallet request sent, wallet ID: ${walletID}`);\n\n  // Wait for result and handle cleanup\n  process.on(\"SIGINT\", async () =\u003e {\n    await mpcClient.cleanup();\n    await nc.drain();\n    process.exit(0);\n  });\n}\n```\n\n### Signing a Solana Transaction\n\n```ts\nimport { connect } from \"nats\";\nimport { MpciumClient, KeyType } from \"@fystack/mpcium-ts\";\nimport {\n  Connection,\n  Transaction,\n  SystemProgram,\n  PublicKey,\n  LAMPORTS_PER_SOL,\n} from \"@solana/web3.js\";\nimport fs from \"fs\";\n\nasync function signSolanaTransaction(walletId) {\n  const nc = await connect({ servers: \"nats://localhost:4222\" });\n  const mpcClient = await MpciumClient.create({\n    nc: nc,\n    keyPath: \"./event_initiator.key\",\n  });\n\n  // Get wallet information from wallets.json\n  const walletsFile = \"./examples/wallets.json\";\n  const wallets = JSON.parse(fs.readFileSync(walletsFile, \"utf8\"));\n  const wallet = wallets[walletId];\n\n  if (!wallet) {\n    throw new Error(`Wallet ${walletId} not found`);\n  }\n\n  // Connect to Solana devnet\n  const connection = new Connection(\n    \"https://api.devnet.solana.com\",\n    \"confirmed\"\n  );\n\n  // Create public key from wallet data\n  const publicKeyBuffer = Buffer.from(wallet.eddsa_pub_key, \"base64\");\n  const fromPublicKey = new PublicKey(publicKeyBuffer);\n\n  // Create transaction\n  const transaction = new Transaction().add(\n    SystemProgram.transfer({\n      fromPubkey: fromPublicKey,\n      toPubkey: new PublicKey(\"4LKprD1XvTuBupHqWXoS42XsEBHp7qALo3giDBRCNhAV\"),\n      lamports: LAMPORTS_PER_SOL * 0.01,\n    })\n  );\n\n  // Get recent blockhash\n  const { blockhash } = await connection.getLatestBlockhash();\n  transaction.recentBlockhash = blockhash;\n  transaction.feePayer = fromPublicKey;\n\n  // Serialize transaction message\n  const serializedTx = transaction.serializeMessage();\n\n  // Listen for signing results\n  mpcClient.onSignResult((event) =\u003e {\n    if (event.result_type === 1) {\n      // Success\n      const signature = Buffer.from(event.signature, \"base64\");\n      transaction.addSignature(fromPublicKey, signature);\n\n      if (transaction.verifySignatures()) {\n        connection\n          .sendRawTransaction(transaction.serialize())\n          .then((txId) =\u003e console.log(`Transaction sent: ${txId}`));\n      }\n    }\n  });\n\n  // Send signing request\n  await mpcClient.signTransaction({\n    walletId: walletId,\n    keyType: KeyType.Ed25519,\n    networkInternalCode: \"solana:devnet\",\n    tx: Buffer.from(serializedTx).toString(\"base64\"),\n  });\n}\n```\n\n[Full example: sign-solana.ts](./examples/sign-solana.ts)\n\n### Signing a Polkadot Transaction (Native Token Transfer)\n\n```ts\nimport { connect } from \"nats\";\nimport {\n  MpciumClient,\n  KeyType,\n  buildNativeTransferPayload,\n  submitSignedExtrinsic,\n  ed25519PubKeyToSubstrateAddress,\n  getNetworkCode,\n  POLKADOT_NETWORKS,\n} from \"@fystack/mpcium-ts\";\nimport { SigningResultType } from \"@fystack/mpcium-ts\";\nimport { u8aToHex } from \"@polkadot/util\";\nimport fs from \"fs\";\n\nasync function signPolkadotTransaction(walletId: string) {\n  const nc = await connect({ servers: \"nats://localhost:4222\" });\n  const mpcClient = await MpciumClient.create({\n    nc: nc,\n    keyPath: \"./event_initiator.key\",\n  });\n\n  // Load wallet from wallets.json\n  const wallets = JSON.parse(fs.readFileSync(\"./wallets.json\", \"utf8\"));\n  const wallet = wallets[walletId];\n\n  if (!wallet?.eddsa_pub_key) {\n    throw new Error(`Wallet ${walletId} not found or missing EdDSA key`);\n  }\n\n  // Convert EdDSA public key to Substrate address\n  const senderAddress = ed25519PubKeyToSubstrateAddress(\n    wallet.eddsa_pub_key,\n    POLKADOT_NETWORKS.westend.ss58Prefix // Use Westend testnet\n  );\n\n  // Build signing payload for native token transfer\n  const payloadResult = await buildNativeTransferPayload({\n    mpcAddress: senderAddress,\n    destinationAddress: \"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY\",\n    amount: BigInt(100_000_000_000), // 0.1 WND\n    network: \"westend\",\n    keepAlive: true,\n  });\n\n  // Listen for signing results\n  mpcClient.onSignResult(async (event) =\u003e {\n    if (event.result_type === SigningResultType.Success) {\n      const sigBytes = Buffer.from(event.signature, \"base64\");\n      const signatureHex = u8aToHex(sigBytes);\n\n      // Submit signed extrinsic\n      const result = await submitSignedExtrinsic({\n        api: payloadResult.api,\n        extrinsic: payloadResult.extrinsic,\n        signatureHex: signatureHex,\n        mpcAddress: senderAddress,\n      });\n\n      console.log(`Transaction submitted: ${result.txHash}`);\n    }\n  });\n\n  // Send signing request\n  await mpcClient.signTransaction({\n    walletId: walletId,\n    keyType: KeyType.Ed25519,\n    networkInternalCode: getNetworkCode(\"westend\"),\n    tx: Buffer.from(payloadResult.payloadBytes).toString(\"base64\"),\n  });\n}\n```\n\n[Full example: sign-polkadot.ts](./examples/sign-polkadot.ts)\n\n### Signing an Asset Hub Transaction (Asset Transfer)\n\n```ts\nimport { connect } from \"nats\";\nimport {\n  MpciumClient,\n  KeyType,\n  buildAssetTransferPayload,\n  submitSignedExtrinsic,\n  ed25519PubKeyToSubstrateAddress,\n  getNetworkCode,\n  POLKADOT_NETWORKS,\n} from \"@fystack/mpcium-ts\";\nimport { SigningResultType } from \"@fystack/mpcium-ts\";\nimport { u8aToHex } from \"@polkadot/util\";\nimport fs from \"fs\";\n\nasync function signAssetHubTransaction(walletId: string, assetId: number) {\n  const nc = await connect({ servers: \"nats://localhost:4222\" });\n  const mpcClient = await MpciumClient.create({\n    nc: nc,\n    keyPath: \"./event_initiator.key\",\n  });\n\n  // Load wallet from wallets.json\n  const wallets = JSON.parse(fs.readFileSync(\"./wallets.json\", \"utf8\"));\n  const wallet = wallets[walletId];\n\n  if (!wallet?.eddsa_pub_key) {\n    throw new Error(`Wallet ${walletId} not found or missing EdDSA key`);\n  }\n\n  // Convert EdDSA public key to Substrate address\n  const senderAddress = ed25519PubKeyToSubstrateAddress(\n    wallet.eddsa_pub_key,\n    POLKADOT_NETWORKS[\"asset-hub-westend\"].ss58Prefix\n  );\n\n  // Build signing payload for asset transfer\n  const payloadResult = await buildAssetTransferPayload({\n    mpcAddress: senderAddress,\n    assetId: assetId,\n    destinationAddress: \"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY\",\n    amount: BigInt(1_000_000),\n    network: \"asset-hub-westend\",\n  });\n\n  // Listen for signing results\n  mpcClient.onSignResult(async (event) =\u003e {\n    if (event.result_type === SigningResultType.Success) {\n      const sigBytes = Buffer.from(event.signature, \"base64\");\n      const signatureHex = u8aToHex(sigBytes);\n\n      // Submit signed extrinsic\n      const result = await submitSignedExtrinsic({\n        api: payloadResult.api,\n        extrinsic: payloadResult.extrinsic,\n        signatureHex: signatureHex,\n        mpcAddress: senderAddress,\n      });\n\n      console.log(`Transaction submitted: ${result.txHash}`);\n    }\n  });\n\n  // Send signing request\n  await mpcClient.signTransaction({\n    walletId: walletId,\n    keyType: KeyType.Ed25519,\n    networkInternalCode: getNetworkCode(\"asset-hub-westend\"),\n    tx: Buffer.from(payloadResult.payloadBytes).toString(\"base64\"),\n  });\n}\n```\n\n[Full example: sign-polkadot-asset-hub.ts](./examples/sign-polkadot-asset-hub.ts)\n\n### Resharing MPC Keys\n\nResharing allows you to change the threshold and/or participants in an MPC wallet without exposing the private key. This is useful for:\n\n- Adding or removing participants from a wallet\n- Changing the threshold (e.g., from 2-of-3 to 3-of-5)\n- Key rotation for security purposes\n\n#### Resharing an Ethereum Wallet\n\n```ts\nimport { connect } from \"nats\";\nimport { MpciumClient, KeyType } from \"@fystack/mpcium-ts\";\nimport fs from \"fs\";\n\nasync function reshareEthereumWallet(walletId: string) {\n  const nc = await connect({ servers: \"nats://localhost:4222\" });\n  const mpcClient = await MpciumClient.create({\n    nc: nc,\n    keyPath: \"./event_initiator.key\",\n  });\n\n  // Listen for resharing results\n  mpcClient.onResharingResult((event) =\u003e {\n    console.log(\"Resharing result:\", event);\n\n    if (event.result_type === \"success\") {\n      // Update wallet with new public key\n      const wallets = JSON.parse(fs.readFileSync(\"./wallets.json\", \"utf8\"));\n      wallets[walletId].ecdsa_pub_key = event.pub_key;\n      wallets[walletId].reshared = true;\n      wallets[walletId].new_threshold = event.new_threshold;\n\n      fs.writeFileSync(\"./wallets.json\", JSON.stringify(wallets, null, 2));\n      console.log(\"Wallet updated with new reshared key\");\n    }\n  });\n\n  // Initiate resharing with new node configuration\n  const sessionId = await mpcClient.reshareKeys({\n    walletId: walletId,\n    nodeIds: [\"node0\", \"node1\", \"node2\", \"node3\"], // Add new node\n    newThreshold: 3, // Change from 2-of-3 to 3-of-4\n    keyType: KeyType.Secp256k1,\n  });\n\n  console.log(`Resharing initiated with session ID: ${sessionId}`);\n}\n```\n\n#### Resharing a Solana Wallet\n\n```ts\n// Similar to Ethereum but using Ed25519 keys\nconst sessionId = await mpcClient.reshareKeys({\n  walletId: walletId,\n  nodeIds: [\"node0\", \"node1\", \"node2\"],\n  newThreshold: 2,\n  keyType: KeyType.Ed25519,\n});\n```\n\n[Full examples: reshare-eth.ts](./examples/reshare-eth.ts) | [reshare-solana.ts](./examples/reshare-solana.ts)\n\n## Tests\n\n### 1. Generate an MPC wallet\n\n```\nnpx ts-node ./examples/generate-wallet.ts\n```\n\n```\nConnected to NATS at localhost:4222\nSubscribed to wallet creation results\nCreateWallet request sent for wallet: a99900b2-0ef8-4d7e-8c3f-2ef85abbae4c\nCreateWallet sent, awaiting result... walletID: a99900b2-0ef8-4d7e-8c3f-2ef85abbae4c\nReceived wallet creation result: {\n  wallet_id: 'a99900b2-0ef8-4d7e-8c3f-2ef85abbae4c',\n  ecdsa_pub_key: '1ftOqTd9z540F7J6bSLJJ8gqn85HlyQKetWB4mACDFBhaodgiNr9ILL5wZ95yWpaqQc77f02rQklUeDSZhLVVA==',\n  eddsa_pub_key: 'm0qUKZlxmzgYA9sRh1Q7cQJHT8jEdUQjbic8hQNHG2o='\n}\nSolana wallet address: BTC9kvDchPvu84iMzLbhYBg5bWma4QHDAFumpF41ErjT\nEthereum wallet address: 0x309bdE4d218e44E4a391f4c43Bf6226156D3255b\nWallet saved to wallets.json with ID: a99900b2-0ef8-4d7e-8c3f-2ef85abbae4c\n\n```\n\n### 2. Transfer Solana to the wallet\n\n- Use Phantom to transfer SOL from devnet to the wallet\n\n###\n\n### 3. Sign a Solana transaction\n\n```\nnpx ts-node ./examples/sign-solana.ts a99900b2-0ef8-4d7e-8c3f-2ef85abbae4c\n```\n\n### 4. Sign an Ethereum transaction\n\n```\nnpx ts-node ./examples/sign-eth.ts a99900b2-0ef8-4d7e-8c3f-2ef85abbae4c\n```\n\n### 5. Sign a Polkadot transaction (Native Token Transfer)\n\n```\nnpx ts-node ./examples/sign-polkadot.ts a99900b2-0ef8-4d7e-8c3f-2ef85abbae4c\n```\n\n### 6. Sign an Asset Hub transaction (Asset Transfer)\n\n```\nnpx ts-node ./examples/sign-polkadot-asset-hub.ts a99900b2-0ef8-4d7e-8c3f-2ef85abbae4c 1984\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffystack%2Fmpcium-client-ts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffystack%2Fmpcium-client-ts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffystack%2Fmpcium-client-ts/lists"}