|
7 | 7 | recoverPublicKey, |
8 | 8 | serializeSignature, |
9 | 9 | sha256, |
| 10 | + fromHex, |
10 | 11 | type Address, |
11 | 12 | type Hex, |
12 | 13 | } from "viem"; |
@@ -66,6 +67,23 @@ export interface BaseSignerClientParams { |
66 | 67 | rpId?: string; |
67 | 68 | } |
68 | 69 |
|
| 70 | +export interface ExportPrivateKeyParams { |
| 71 | + type: "SOLANA" | "ETHEREUM"; |
| 72 | + client?: TurnkeyClient; |
| 73 | + orgId?: string; |
| 74 | +} |
| 75 | + |
| 76 | +export interface MultiOwnerExportPrivateKeyParams { |
| 77 | + type: "SOLANA" | "ETHEREUM"; |
| 78 | + orgId: string; |
| 79 | +} |
| 80 | + |
| 81 | +export interface ExportPrivateKeyEncryptedResult { |
| 82 | + exportBundle: string; |
| 83 | + ciphertext: string; |
| 84 | + encapsulatedKey: string; |
| 85 | +} |
| 86 | + |
69 | 87 | export type ExportWalletStamper = TurnkeyClient["stamper"] & { |
70 | 88 | injectWalletExportBundle(bundle: string, orgId: string): Promise<boolean>; |
71 | 89 | injectKeyExportBundle(bundle: string, orgId: string): Promise<boolean>; |
@@ -1491,4 +1509,73 @@ export abstract class BaseSignerClient< |
1491 | 1509 | protected getOauthNonce = (turnkeyPublicKey: string): string => { |
1492 | 1510 | return sha256(new TextEncoder().encode(turnkeyPublicKey)).slice(2); |
1493 | 1511 | }; |
| 1512 | + |
| 1513 | + /** |
| 1514 | + * Exports a private key for a given account encrypted with the provided public key |
| 1515 | + * |
| 1516 | + * @param {ExportPrivateKeyParams} opts the parameters for the export |
| 1517 | + * @returns {Promise<string>} the private key |
| 1518 | + */ |
| 1519 | + public exportPrivateKeyEncrypted = async ( |
| 1520 | + opts: ExportPrivateKeyParams & { encryptWith: string }, |
| 1521 | + ): Promise<ExportPrivateKeyEncryptedResult> => { |
| 1522 | + if (!this.user) { |
| 1523 | + throw new NotAuthenticatedError(); |
| 1524 | + } |
| 1525 | + |
| 1526 | + const targetAddressFormat = |
| 1527 | + opts.type === "ETHEREUM" |
| 1528 | + ? "ADDRESS_FORMAT_ETHEREUM" |
| 1529 | + : "ADDRESS_FORMAT_SOLANA"; |
| 1530 | + const turnkeyClient = opts.client ?? this.turnkeyClient; |
| 1531 | + const organizationId = opts.orgId ?? this.user.orgId; |
| 1532 | + |
| 1533 | + const wallets = await turnkeyClient.getWalletAccounts({ organizationId }); |
| 1534 | + const account = wallets.accounts.find( |
| 1535 | + (account) => account.addressFormat === targetAddressFormat, |
| 1536 | + ); |
| 1537 | + if (!account?.address) { |
| 1538 | + throw new Error("Failed to find account: " + opts.type); |
| 1539 | + } |
| 1540 | + const exported = await turnkeyClient.exportWalletAccount({ |
| 1541 | + organizationId, |
| 1542 | + type: "ACTIVITY_TYPE_EXPORT_WALLET_ACCOUNT", |
| 1543 | + timestampMs: Date.now().toString(), |
| 1544 | + parameters: { |
| 1545 | + address: account.address, |
| 1546 | + targetPublicKey: opts.encryptWith, |
| 1547 | + }, |
| 1548 | + }); |
| 1549 | + const exportBundle = |
| 1550 | + exported?.activity.result.exportWalletAccountResult?.exportBundle; |
| 1551 | + if (!exportBundle) throw new Error("No export bundle found"); |
| 1552 | + |
| 1553 | + const parsedExportBundle = JSON.parse(exportBundle); |
| 1554 | + const signedData = JSON.parse( |
| 1555 | + fromHex(`0x${parsedExportBundle.data}`, { to: "string" }), |
| 1556 | + ); |
| 1557 | + |
| 1558 | + return { |
| 1559 | + exportBundle, |
| 1560 | + ciphertext: signedData.ciphertext, |
| 1561 | + encapsulatedKey: signedData.encappedPublic, |
| 1562 | + }; |
| 1563 | + }; |
| 1564 | + |
| 1565 | + /** |
| 1566 | + * Exports a private key for a given account in a multi-owner org |
| 1567 | + * |
| 1568 | + * @param {MultiOwnerExportPrivateKeyParams} opts the parameters for the export |
| 1569 | + * @returns {Promise<string>} the private key |
| 1570 | + */ |
| 1571 | + public experimental_multiOwnerExportPrivateKeyEncrypted = async ( |
| 1572 | + opts: MultiOwnerExportPrivateKeyParams & { encryptWith: string }, |
| 1573 | + ): Promise<ExportPrivateKeyEncryptedResult> => { |
| 1574 | + return this.exportPrivateKeyEncrypted({ |
| 1575 | + type: opts.type, |
| 1576 | + client: this.experimental_createMultiOwnerTurnkeyClient(), |
| 1577 | + orgId: opts.orgId, |
| 1578 | + encryptWith: opts.encryptWith, |
| 1579 | + }); |
| 1580 | + }; |
1494 | 1581 | } |
0 commit comments