@zerodev/wallet-core 0.0.1-alpha.4 → 0.0.1-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +43 -2
  2. package/dist/_cjs/actions/wallet/getUserWallet.js +6 -1
  3. package/dist/_cjs/actions/wallet/getUserWallet.js.map +1 -1
  4. package/dist/_cjs/adapters/viem.js +3 -2
  5. package/dist/_cjs/adapters/viem.js.map +1 -1
  6. package/dist/_cjs/client/transports/rest.js +8 -2
  7. package/dist/_cjs/client/transports/rest.js.map +1 -1
  8. package/dist/_cjs/core/createZeroDevWallet.js +1 -0
  9. package/dist/_cjs/core/createZeroDevWallet.js.map +1 -1
  10. package/dist/_cjs/index.js +3 -1
  11. package/dist/_cjs/index.js.map +1 -1
  12. package/dist/_cjs/stampers/iframeStamper.js +3 -0
  13. package/dist/_cjs/stampers/iframeStamper.js.map +1 -1
  14. package/dist/_cjs/utils/exportPrivateKey.js +55 -0
  15. package/dist/_cjs/utils/exportPrivateKey.js.map +1 -0
  16. package/dist/_esm/actions/wallet/getUserWallet.js +7 -2
  17. package/dist/_esm/actions/wallet/getUserWallet.js.map +1 -1
  18. package/dist/_esm/adapters/viem.js +3 -2
  19. package/dist/_esm/adapters/viem.js.map +1 -1
  20. package/dist/_esm/client/transports/rest.js +8 -2
  21. package/dist/_esm/client/transports/rest.js.map +1 -1
  22. package/dist/_esm/core/createZeroDevWallet.js +1 -0
  23. package/dist/_esm/core/createZeroDevWallet.js.map +1 -1
  24. package/dist/_esm/index.js +1 -0
  25. package/dist/_esm/index.js.map +1 -1
  26. package/dist/_esm/stampers/iframeStamper.js +4 -1
  27. package/dist/_esm/stampers/iframeStamper.js.map +1 -1
  28. package/dist/_esm/utils/exportPrivateKey.js +83 -0
  29. package/dist/_esm/utils/exportPrivateKey.js.map +1 -0
  30. package/dist/_types/actions/wallet/getUserWallet.d.ts +4 -2
  31. package/dist/_types/actions/wallet/getUserWallet.d.ts.map +1 -1
  32. package/dist/_types/adapters/viem.d.ts +1 -0
  33. package/dist/_types/adapters/viem.d.ts.map +1 -1
  34. package/dist/_types/client/transports/rest.d.ts +1 -0
  35. package/dist/_types/client/transports/rest.d.ts.map +1 -1
  36. package/dist/_types/core/createZeroDevWallet.d.ts.map +1 -1
  37. package/dist/_types/index.d.ts +2 -0
  38. package/dist/_types/index.d.ts.map +1 -1
  39. package/dist/_types/stampers/iframeStamper.d.ts.map +1 -1
  40. package/dist/_types/stampers/types.d.ts +2 -0
  41. package/dist/_types/stampers/types.d.ts.map +1 -1
  42. package/dist/_types/utils/exportPrivateKey.d.ts +47 -0
  43. package/dist/_types/utils/exportPrivateKey.d.ts.map +1 -0
  44. package/dist/tsconfig.build.tsbuildinfo +1 -1
  45. package/package.json +1 -1
  46. package/src/actions/wallet/getUserWallet.ts +10 -3
  47. package/src/adapters/viem.ts +4 -2
  48. package/src/client/transports/rest.ts +8 -2
  49. package/src/core/createZeroDevWallet.ts +1 -0
  50. package/src/index.ts +2 -0
  51. package/src/stampers/iframeStamper.ts +16 -2
  52. package/src/stampers/types.ts +7 -0
  53. package/src/utils/exportPrivateKey.ts +116 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerodev/wallet-core",
3
- "version": "0.0.1-alpha.4",
3
+ "version": "0.0.1-alpha.6",
4
4
  "description": "ZeroDev Wallet SDK built on Turnkey",
5
5
  "main": "./dist/_cjs/index.js",
6
6
  "module": "./dist/_esm/index.js",
@@ -6,11 +6,13 @@ export type GetUserWalletParameters = {
6
6
  organizationId: string
7
7
  /** The project ID for the request */
8
8
  projectId: string
9
+ /** The token for the request */
10
+ token: string
9
11
  }
10
12
 
11
13
  export type GetUserWalletReturnType = {
12
14
  /** The wallet address */
13
- walletAddress: Hex
15
+ walletAddresses: Hex[]
14
16
  /** The user ID */
15
17
  userId?: string
16
18
  }
@@ -28,19 +30,24 @@ export type GetUserWalletReturnType = {
28
30
  * organizationId: 'org_123',
29
31
  * projectId: 'proj_456'
30
32
  * });
31
- * console.log(wallet.walletAddress); // '0x...'
33
+ * console.log(wallet.walletAddresses); // ['0x...', '0x...']
32
34
  * ```
33
35
  */
34
36
  export async function getUserWallet(
35
37
  client: Client,
36
38
  params: GetUserWalletParameters,
37
39
  ): Promise<GetUserWalletReturnType> {
38
- const { organizationId, projectId } = params
40
+ const { organizationId, projectId, token } = params
39
41
 
40
42
  return await client.request({
41
43
  path: `${projectId}/user-wallet`,
42
44
  body: {
43
45
  organizationId,
44
46
  },
47
+ headers: {
48
+ Authorization: `Bearer ${token}`,
49
+ },
50
+ stamp: true,
51
+ stampPostion: 'headers',
45
52
  })
46
53
  }
@@ -24,12 +24,13 @@ export interface ToViemAccountParams {
24
24
  client: ZeroDevWalletClient
25
25
  organizationId: string
26
26
  projectId: string
27
+ token: string
27
28
  }
28
29
 
29
30
  export async function toViemAccount(
30
31
  params: ToViemAccountParams,
31
32
  ): Promise<LocalAccount> {
32
- const { client, organizationId, projectId } = params
33
+ const { client, organizationId, projectId, token } = params
33
34
 
34
35
  let address: Hex = zeroAddress
35
36
 
@@ -37,8 +38,9 @@ export async function toViemAccount(
37
38
  const walletResponse = await client.getUserWallet({
38
39
  organizationId,
39
40
  projectId,
41
+ token,
40
42
  })
41
- address = walletResponse.walletAddress
43
+ address = walletResponse.walletAddresses[0]
42
44
  } catch {
43
45
  address = zeroAddress
44
46
  }
@@ -8,6 +8,7 @@ export type RestRequestArgs = {
8
8
  headers?: Record<string, string>
9
9
  stamp?: boolean
10
10
  stampWith?: 'indexedDb' | 'webAuthn'
11
+ stampPostion?: 'body' | 'headers'
11
12
  }
12
13
 
13
14
  export type RestRequestFn = <T = any>(args: RestRequestArgs) => Promise<T>
@@ -44,7 +45,7 @@ export function rest(url: string, cfg: RestTransportConfig): RestTransport {
44
45
 
45
46
  try {
46
47
  let requestBody = args.body
47
- const requestHeaders = {
48
+ let requestHeaders = {
48
49
  'content-type': 'application/json',
49
50
  ...(args.headers ?? {}),
50
51
  ...(cfg.fetchOptions?.headers ?? {}),
@@ -65,7 +66,12 @@ export function rest(url: string, cfg: RestTransportConfig): RestTransport {
65
66
  const stamp = await stamper.stamp(bodyString)
66
67
 
67
68
  // Restructure request body to match backend expectation
68
- if (body) {
69
+ if (args.stampPostion === 'headers') {
70
+ requestHeaders = {
71
+ ...requestHeaders,
72
+ [stamp.stampHeaderName]: stamp.stampHeaderValue,
73
+ }
74
+ } else if (body) {
69
75
  requestBody = {
70
76
  body: bodyString,
71
77
  stamp: {
@@ -422,6 +422,7 @@ export async function createZeroDevWallet(
422
422
  client,
423
423
  organizationId: session.organizationId,
424
424
  projectId,
425
+ token: session.token ?? '',
425
426
  })
426
427
  },
427
428
  }
package/src/index.ts CHANGED
@@ -70,6 +70,8 @@ export type {
70
70
  export type { StorageAdapter, StorageManager } from './storage/manager.js'
71
71
  // Session types
72
72
  export type { StamperType, ZeroDevWalletSession } from './types/session.js'
73
+ export type { KeyFormat } from './utils/exportPrivateKey.js'
74
+ export { exportPrivateKey } from './utils/exportPrivateKey.js'
73
75
  export { exportWallet } from './utils/exportWallet.js'
74
76
  // Utils
75
77
  export { normalizeTimestamp } from './utils/utils.js'
@@ -1,5 +1,8 @@
1
- import { IframeStamper as TurnkeyIframeStamper } from '@turnkey/iframe-stamper'
2
- import type { IframeStamper } from './types.js'
1
+ import {
2
+ KeyFormat,
3
+ IframeStamper as TurnkeyIframeStamper,
4
+ } from '@turnkey/iframe-stamper'
5
+ import type { IframeStamper, KeyFormat as KeyFormatType } from './types.js'
3
6
 
4
7
  export async function createIframeStamper(cfg: {
5
8
  iframeUrl: string
@@ -31,5 +34,16 @@ export async function createIframeStamper(cfg: {
31
34
  async injectWalletExportBundle(bundle: string, organizationId: string) {
32
35
  return await inner.injectWalletExportBundle(bundle, organizationId)
33
36
  },
37
+ async injectKeyExportBundle(
38
+ bundle: string,
39
+ organizationId: string,
40
+ keyFormat?: KeyFormatType,
41
+ ) {
42
+ return await inner.injectKeyExportBundle(
43
+ bundle,
44
+ organizationId,
45
+ keyFormat ? KeyFormat[keyFormat] : KeyFormat.Hexadecimal,
46
+ )
47
+ },
34
48
  }
35
49
  }
@@ -13,6 +13,8 @@ export type Stamper = {
13
13
  clear: () => Promise<void>
14
14
  }
15
15
 
16
+ export type KeyFormat = 'Hexadecimal' | 'Solana'
17
+
16
18
  export type IframeStamper = Stamper & {
17
19
  init(): Promise<string>
18
20
  injectCredentialBundle(bundle: string): Promise<boolean>
@@ -20,6 +22,11 @@ export type IframeStamper = Stamper & {
20
22
  bundle: string,
21
23
  organizationId: string,
22
24
  ): Promise<boolean>
25
+ injectKeyExportBundle(
26
+ bundle: string,
27
+ organizationId: string,
28
+ keyFormat?: KeyFormat,
29
+ ): Promise<boolean>
23
30
  }
24
31
 
25
32
  export type IndexedDbStamper = Stamper & {
@@ -0,0 +1,116 @@
1
+ import type { ZeroDevWalletSDK } from '../core/createZeroDevWallet.js'
2
+ import type { KeyFormat } from '../stampers/types.js'
3
+
4
+ export type ExportPrivateKeyParameters = {
5
+ /** Wallet to use for the export */
6
+ wallet: ZeroDevWalletSDK
7
+ /** Target public key from export iframe for encryption */
8
+ targetPublicKey: string
9
+ /** Wallet address to export (optional, defaults to wallet's account address) */
10
+ address?: string
11
+ }
12
+
13
+ /**
14
+ * Export a wallet account's private key
15
+ *
16
+ * This calls Turnkey's export_wallet_account API to get an encrypted bundle
17
+ * containing the account's private key. The bundle is encrypted with the
18
+ * targetPublicKey (from Turnkey's export iframe).
19
+ *
20
+ * @param params - Export parameters
21
+ * @returns Encrypted export bundle and metadata
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * // In UI: Initialize export iframe first
26
+ * const iframeStamper = await createIframeStamper({
27
+ * iframeUrl: 'https://export.turnkey.com',
28
+ * iframeContainer: document.getElementById('export-container'),
29
+ * iframeElementId: 'export-iframe'
30
+ * });
31
+ * const targetPublicKey = await iframeStamper.init();
32
+ *
33
+ * // Call SDK to get encrypted bundle
34
+ * const { exportBundle, address, organizationId } = await exportPrivateKey({
35
+ * wallet,
36
+ * targetPublicKey
37
+ * });
38
+ *
39
+ * // Inject into iframe to display private key
40
+ * await iframeStamper.injectKeyExportBundle(exportBundle, organizationId, 'Hexadecimal');
41
+ * ```
42
+ */
43
+ export async function exportPrivateKey(
44
+ params: ExportPrivateKeyParameters,
45
+ ): Promise<{ exportBundle: string; address: string; organizationId: string }> {
46
+ const { targetPublicKey, wallet, address: addressParam } = params
47
+
48
+ const session = await wallet.getSession()
49
+ if (!session) {
50
+ throw new Error('Session not found')
51
+ }
52
+ const { organizationId } = session
53
+
54
+ // If address not provided, get it from the wallet's account
55
+ let address = addressParam
56
+ if (!address) {
57
+ const account = await wallet.toAccount()
58
+ if (!account?.address) {
59
+ throw new Error('Could not get address from wallet account')
60
+ }
61
+ address = account.address
62
+ }
63
+
64
+ const exportBody = JSON.stringify({
65
+ type: 'ACTIVITY_TYPE_EXPORT_WALLET_ACCOUNT',
66
+ timestampMs: Date.now().toString(),
67
+ organizationId: organizationId,
68
+ parameters: {
69
+ address: address,
70
+ targetPublicKey,
71
+ },
72
+ })
73
+
74
+ const stamperKey =
75
+ session.stamperType === 'indexedDb' ? 'indexedDbStamper' : 'webauthnStamper'
76
+ const stamper = wallet.client[stamperKey]
77
+ if (!stamper) {
78
+ throw new Error(`Stamper '${stamperKey}' not found on wallet.client`)
79
+ }
80
+
81
+ const exportStamp = await stamper.stamp(exportBody)
82
+ if (!exportStamp) {
83
+ throw new Error('Failed to stamp export body')
84
+ }
85
+
86
+ const exportResponse = await fetch(
87
+ 'https://api.turnkey.com/public/v1/submit/export_wallet_account',
88
+ {
89
+ method: 'POST',
90
+ body: exportBody,
91
+ headers: {
92
+ [exportStamp.stampHeaderName]: exportStamp.stampHeaderValue,
93
+ },
94
+ },
95
+ )
96
+ if (!exportResponse.ok) {
97
+ const errorText = await exportResponse.text()
98
+ throw new Error(
99
+ `Failed to export wallet account: ${exportResponse.status} ${errorText}`,
100
+ )
101
+ }
102
+ const exportData = await exportResponse.json()
103
+
104
+ const exportBundle =
105
+ exportData?.activity?.result?.exportWalletAccountResult?.exportBundle
106
+
107
+ if (!exportBundle) {
108
+ throw new Error(
109
+ `Export bundle not found in response: ${JSON.stringify(exportData)}`,
110
+ )
111
+ }
112
+
113
+ return { exportBundle, address: address!, organizationId }
114
+ }
115
+
116
+ export type { KeyFormat }