@kadi.build/deploy-ability 0.0.1

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 (198) hide show
  1. package/README.md +523 -0
  2. package/dist/constants.d.ts +82 -0
  3. package/dist/constants.d.ts.map +1 -0
  4. package/dist/constants.js +82 -0
  5. package/dist/constants.js.map +1 -0
  6. package/dist/errors/certificate-error.d.ts +95 -0
  7. package/dist/errors/certificate-error.d.ts.map +1 -0
  8. package/dist/errors/certificate-error.js +111 -0
  9. package/dist/errors/certificate-error.js.map +1 -0
  10. package/dist/errors/deployment-error.d.ts +122 -0
  11. package/dist/errors/deployment-error.d.ts.map +1 -0
  12. package/dist/errors/deployment-error.js +185 -0
  13. package/dist/errors/deployment-error.js.map +1 -0
  14. package/dist/errors/index.d.ts +13 -0
  15. package/dist/errors/index.d.ts.map +1 -0
  16. package/dist/errors/index.js +18 -0
  17. package/dist/errors/index.js.map +1 -0
  18. package/dist/errors/profile-error.d.ts +106 -0
  19. package/dist/errors/profile-error.d.ts.map +1 -0
  20. package/dist/errors/profile-error.js +127 -0
  21. package/dist/errors/profile-error.js.map +1 -0
  22. package/dist/errors/provider-error.d.ts +104 -0
  23. package/dist/errors/provider-error.d.ts.map +1 -0
  24. package/dist/errors/provider-error.js +120 -0
  25. package/dist/errors/provider-error.js.map +1 -0
  26. package/dist/errors/wallet-error.d.ts +131 -0
  27. package/dist/errors/wallet-error.d.ts.map +1 -0
  28. package/dist/errors/wallet-error.js +154 -0
  29. package/dist/errors/wallet-error.js.map +1 -0
  30. package/dist/index.d.ts +49 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +53 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/targets/akash/bid-selectors.d.ts +251 -0
  35. package/dist/targets/akash/bid-selectors.d.ts.map +1 -0
  36. package/dist/targets/akash/bid-selectors.js +322 -0
  37. package/dist/targets/akash/bid-selectors.js.map +1 -0
  38. package/dist/targets/akash/bid-types.d.ts +297 -0
  39. package/dist/targets/akash/bid-types.d.ts.map +1 -0
  40. package/dist/targets/akash/bid-types.js +89 -0
  41. package/dist/targets/akash/bid-types.js.map +1 -0
  42. package/dist/targets/akash/blockchain-client.d.ts +577 -0
  43. package/dist/targets/akash/blockchain-client.d.ts.map +1 -0
  44. package/dist/targets/akash/blockchain-client.js +803 -0
  45. package/dist/targets/akash/blockchain-client.js.map +1 -0
  46. package/dist/targets/akash/certificate-manager.d.ts +228 -0
  47. package/dist/targets/akash/certificate-manager.d.ts.map +1 -0
  48. package/dist/targets/akash/certificate-manager.js +395 -0
  49. package/dist/targets/akash/certificate-manager.js.map +1 -0
  50. package/dist/targets/akash/constants.d.ts +231 -0
  51. package/dist/targets/akash/constants.d.ts.map +1 -0
  52. package/dist/targets/akash/constants.js +225 -0
  53. package/dist/targets/akash/constants.js.map +1 -0
  54. package/dist/targets/akash/deployer.d.ts +136 -0
  55. package/dist/targets/akash/deployer.d.ts.map +1 -0
  56. package/dist/targets/akash/deployer.js +599 -0
  57. package/dist/targets/akash/deployer.js.map +1 -0
  58. package/dist/targets/akash/environment.d.ts +241 -0
  59. package/dist/targets/akash/environment.d.ts.map +1 -0
  60. package/dist/targets/akash/environment.js +245 -0
  61. package/dist/targets/akash/environment.js.map +1 -0
  62. package/dist/targets/akash/index.d.ts +1113 -0
  63. package/dist/targets/akash/index.d.ts.map +1 -0
  64. package/dist/targets/akash/index.js +909 -0
  65. package/dist/targets/akash/index.js.map +1 -0
  66. package/dist/targets/akash/lease-monitor.d.ts +51 -0
  67. package/dist/targets/akash/lease-monitor.d.ts.map +1 -0
  68. package/dist/targets/akash/lease-monitor.js +110 -0
  69. package/dist/targets/akash/lease-monitor.js.map +1 -0
  70. package/dist/targets/akash/logs.d.ts +71 -0
  71. package/dist/targets/akash/logs.d.ts.map +1 -0
  72. package/dist/targets/akash/logs.js +311 -0
  73. package/dist/targets/akash/logs.js.map +1 -0
  74. package/dist/targets/akash/logs.types.d.ts +102 -0
  75. package/dist/targets/akash/logs.types.d.ts.map +1 -0
  76. package/dist/targets/akash/logs.types.js +9 -0
  77. package/dist/targets/akash/logs.types.js.map +1 -0
  78. package/dist/targets/akash/pricing.d.ts +247 -0
  79. package/dist/targets/akash/pricing.d.ts.map +1 -0
  80. package/dist/targets/akash/pricing.js +246 -0
  81. package/dist/targets/akash/pricing.js.map +1 -0
  82. package/dist/targets/akash/provider-client.d.ts +114 -0
  83. package/dist/targets/akash/provider-client.d.ts.map +1 -0
  84. package/dist/targets/akash/provider-client.js +318 -0
  85. package/dist/targets/akash/provider-client.js.map +1 -0
  86. package/dist/targets/akash/provider-metadata.d.ts +228 -0
  87. package/dist/targets/akash/provider-metadata.d.ts.map +1 -0
  88. package/dist/targets/akash/provider-metadata.js +14 -0
  89. package/dist/targets/akash/provider-metadata.js.map +1 -0
  90. package/dist/targets/akash/provider-service.d.ts +133 -0
  91. package/dist/targets/akash/provider-service.d.ts.map +1 -0
  92. package/dist/targets/akash/provider-service.js +391 -0
  93. package/dist/targets/akash/provider-service.js.map +1 -0
  94. package/dist/targets/akash/query-client.d.ts +125 -0
  95. package/dist/targets/akash/query-client.d.ts.map +1 -0
  96. package/dist/targets/akash/query-client.js +332 -0
  97. package/dist/targets/akash/query-client.js.map +1 -0
  98. package/dist/targets/akash/sdl-generator.d.ts +31 -0
  99. package/dist/targets/akash/sdl-generator.d.ts.map +1 -0
  100. package/dist/targets/akash/sdl-generator.js +279 -0
  101. package/dist/targets/akash/sdl-generator.js.map +1 -0
  102. package/dist/targets/akash/types.d.ts +285 -0
  103. package/dist/targets/akash/types.d.ts.map +1 -0
  104. package/dist/targets/akash/types.js +54 -0
  105. package/dist/targets/akash/types.js.map +1 -0
  106. package/dist/targets/akash/wallet-manager.d.ts +526 -0
  107. package/dist/targets/akash/wallet-manager.d.ts.map +1 -0
  108. package/dist/targets/akash/wallet-manager.js +953 -0
  109. package/dist/targets/akash/wallet-manager.js.map +1 -0
  110. package/dist/targets/local/compose-generator.d.ts +244 -0
  111. package/dist/targets/local/compose-generator.d.ts.map +1 -0
  112. package/dist/targets/local/compose-generator.js +324 -0
  113. package/dist/targets/local/compose-generator.js.map +1 -0
  114. package/dist/targets/local/deployer.d.ts +82 -0
  115. package/dist/targets/local/deployer.d.ts.map +1 -0
  116. package/dist/targets/local/deployer.js +367 -0
  117. package/dist/targets/local/deployer.js.map +1 -0
  118. package/dist/targets/local/engine-manager.d.ts +155 -0
  119. package/dist/targets/local/engine-manager.d.ts.map +1 -0
  120. package/dist/targets/local/engine-manager.js +250 -0
  121. package/dist/targets/local/engine-manager.js.map +1 -0
  122. package/dist/targets/local/index.d.ts +40 -0
  123. package/dist/targets/local/index.d.ts.map +1 -0
  124. package/dist/targets/local/index.js +43 -0
  125. package/dist/targets/local/index.js.map +1 -0
  126. package/dist/targets/local/network-manager.d.ts +160 -0
  127. package/dist/targets/local/network-manager.d.ts.map +1 -0
  128. package/dist/targets/local/network-manager.js +337 -0
  129. package/dist/targets/local/network-manager.js.map +1 -0
  130. package/dist/targets/local/types.d.ts +327 -0
  131. package/dist/targets/local/types.d.ts.map +1 -0
  132. package/dist/targets/local/types.js +9 -0
  133. package/dist/targets/local/types.js.map +1 -0
  134. package/dist/types/common.d.ts +585 -0
  135. package/dist/types/common.d.ts.map +1 -0
  136. package/dist/types/common.js +13 -0
  137. package/dist/types/common.js.map +1 -0
  138. package/dist/types/index.d.ts +15 -0
  139. package/dist/types/index.d.ts.map +1 -0
  140. package/dist/types/index.js +12 -0
  141. package/dist/types/index.js.map +1 -0
  142. package/dist/types/options.d.ts +329 -0
  143. package/dist/types/options.d.ts.map +1 -0
  144. package/dist/types/options.js +10 -0
  145. package/dist/types/options.js.map +1 -0
  146. package/dist/types/profiles.d.ts +329 -0
  147. package/dist/types/profiles.d.ts.map +1 -0
  148. package/dist/types/profiles.js +27 -0
  149. package/dist/types/profiles.js.map +1 -0
  150. package/dist/types/results.d.ts +443 -0
  151. package/dist/types/results.d.ts.map +1 -0
  152. package/dist/types/results.js +64 -0
  153. package/dist/types/results.js.map +1 -0
  154. package/dist/types/validators.d.ts +118 -0
  155. package/dist/types/validators.d.ts.map +1 -0
  156. package/dist/types/validators.js +198 -0
  157. package/dist/types/validators.js.map +1 -0
  158. package/dist/utils/command-runner.d.ts +128 -0
  159. package/dist/utils/command-runner.d.ts.map +1 -0
  160. package/dist/utils/command-runner.js +210 -0
  161. package/dist/utils/command-runner.js.map +1 -0
  162. package/dist/utils/index.d.ts +10 -0
  163. package/dist/utils/index.d.ts.map +1 -0
  164. package/dist/utils/index.js +10 -0
  165. package/dist/utils/index.js.map +1 -0
  166. package/dist/utils/logger.d.ts +68 -0
  167. package/dist/utils/logger.d.ts.map +1 -0
  168. package/dist/utils/logger.js +93 -0
  169. package/dist/utils/logger.js.map +1 -0
  170. package/dist/utils/profile-loader.d.ts +76 -0
  171. package/dist/utils/profile-loader.d.ts.map +1 -0
  172. package/dist/utils/profile-loader.js +194 -0
  173. package/dist/utils/profile-loader.js.map +1 -0
  174. package/dist/utils/registry/index.d.ts +27 -0
  175. package/dist/utils/registry/index.d.ts.map +1 -0
  176. package/dist/utils/registry/index.js +29 -0
  177. package/dist/utils/registry/index.js.map +1 -0
  178. package/dist/utils/registry/manager.d.ts +319 -0
  179. package/dist/utils/registry/manager.d.ts.map +1 -0
  180. package/dist/utils/registry/manager.js +671 -0
  181. package/dist/utils/registry/manager.js.map +1 -0
  182. package/dist/utils/registry/setup.d.ts +135 -0
  183. package/dist/utils/registry/setup.d.ts.map +1 -0
  184. package/dist/utils/registry/setup.js +207 -0
  185. package/dist/utils/registry/setup.js.map +1 -0
  186. package/dist/utils/registry/transformer.d.ts +92 -0
  187. package/dist/utils/registry/transformer.d.ts.map +1 -0
  188. package/dist/utils/registry/transformer.js +131 -0
  189. package/dist/utils/registry/transformer.js.map +1 -0
  190. package/dist/utils/registry/types.d.ts +241 -0
  191. package/dist/utils/registry/types.d.ts.map +1 -0
  192. package/dist/utils/registry/types.js +10 -0
  193. package/dist/utils/registry/types.js.map +1 -0
  194. package/docs/EXAMPLES.md +293 -0
  195. package/docs/PLACEMENT.md +433 -0
  196. package/docs/STORAGE.md +318 -0
  197. package/docs/building-provider-reliability-tracker.md +2581 -0
  198. package/package.json +109 -0
@@ -0,0 +1,953 @@
1
+ /**
2
+ * Akash Network Wallet Connection Module
3
+ *
4
+ * Provides a clean, step-by-step API for connecting to Keplr wallet via WalletConnect.
5
+ * This is a LIBRARY - no QR code display, no prompts, just pure wallet operations.
6
+ *
7
+ * Key Improvements from kadi-deploy:
8
+ * - ✅ ZERO CLI dependencies (no QRCode, chalk, enquirer)
9
+ * - ✅ ZERO `any` types (was 5 any types)
10
+ * - ✅ Split into 4 clear steps for composability
11
+ * - ✅ Result types for all operations
12
+ * - ✅ Natural, intuitive API design
13
+ *
14
+ * Architecture:
15
+ * ```
16
+ * Step 1: initWalletConnect() → Create SignClient
17
+ * ↓
18
+ * Step 2: generateConnectionUri() → Get URI for QR code
19
+ * ↓
20
+ * Step 3: waitForApproval() → Poll for user approval
21
+ * ↓
22
+ * Step 4: createWalletContext() → Get ready-to-use wallet
23
+ * ```
24
+ *
25
+ * Design Philosophy:
26
+ * Each step is independent and composable. Callers can:
27
+ * - Display QR codes however they want (terminal, web, mobile)
28
+ * - Add their own timeout logic
29
+ * - Implement custom retry mechanisms
30
+ * - Show progress however they prefer
31
+ *
32
+ * @module targets/akash/wallet
33
+ */
34
+ import { SignClient } from '@walletconnect/sign-client';
35
+ import { KeplrWalletConnectV2 } from '@keplr-wallet/wc-client';
36
+ import { fromHex } from '@cosmjs/encoding';
37
+ import { StargateClient } from '@cosmjs/stargate';
38
+ import { WalletError, WalletErrorCodes } from '../../errors/index.js';
39
+ import { getNetworkConfig } from './environment.js';
40
+ /**
41
+ * Step 1: Initialize WalletConnect client
42
+ *
43
+ * Creates a WalletConnect SignClient with proper configuration.
44
+ * This is a one-time setup that can be reused for multiple connections.
45
+ *
46
+ * @param projectId - WalletConnect Cloud project ID
47
+ * @param metadata - Optional app metadata (defaults to KADI Deploy)
48
+ * @returns Result with WalletConnect client or error
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * // Initialize with your project ID
53
+ * const clientResult = await initWalletConnect('your-project-id-here');
54
+ *
55
+ * if (!clientResult.success) {
56
+ * console.error('Failed to initialize:', clientResult.error);
57
+ * return;
58
+ * }
59
+ *
60
+ * const wcClient = clientResult.data;
61
+ * console.log('WalletConnect ready!');
62
+ * ```
63
+ */
64
+ export async function initWalletConnect(projectId, metadata) {
65
+ try {
66
+ // Step 1: Validate project ID
67
+ if (!projectId || projectId.trim().length === 0) {
68
+ return {
69
+ success: false,
70
+ error: new WalletError('WalletConnect project ID is required', WalletErrorCodes.MISSING_PROJECT_ID, { projectId })
71
+ };
72
+ }
73
+ // Step 2: Prepare metadata (use defaults if not provided)
74
+ const appMetadata = metadata || {
75
+ name: 'KADI Deploy',
76
+ description: 'Deploy to Akash Network',
77
+ url: 'https://kadi.build',
78
+ icons: ['https://kadi.build/icon.png']
79
+ };
80
+ // Step 3: Initialize SignClient
81
+ // This creates the WalletConnect client that manages all connections
82
+ const client = await SignClient.init({
83
+ projectId,
84
+ metadata: appMetadata
85
+ });
86
+ // Step 4: Return initialized client
87
+ return {
88
+ success: true,
89
+ data: {
90
+ client,
91
+ metadata: appMetadata
92
+ }
93
+ };
94
+ }
95
+ catch (error) {
96
+ // Step 5: Handle initialization errors
97
+ return {
98
+ success: false,
99
+ error: new WalletError(`Failed to initialize WalletConnect: ${error}`, WalletErrorCodes.INIT_FAILED, { error: String(error) })
100
+ };
101
+ }
102
+ }
103
+ /**
104
+ * Step 2: Generate connection URI for QR code display
105
+ *
106
+ * Creates a new pairing and generates the WalletConnect URI.
107
+ * The caller is responsible for displaying this URI as a QR code.
108
+ *
109
+ * @param wcClient - Initialized WalletConnect client from step 1
110
+ * @param network - Akash network to connect to
111
+ * @returns Result with URI and pairing info or error
112
+ *
113
+ * @example
114
+ * ```typescript
115
+ * // Generate URI for QR code
116
+ * const uriResult = await generateConnectionUri(wcClient, 'mainnet');
117
+ *
118
+ * if (!uriResult.success) {
119
+ * console.error('Failed to generate URI:', uriResult.error);
120
+ * return;
121
+ * }
122
+ *
123
+ * const { uri, pairingTopic, approval } = uriResult.data;
124
+ *
125
+ * // Caller displays QR code however they want:
126
+ * // - Terminal: QRCode.generate(uri)
127
+ * // - Web: <QRCode value={uri} />
128
+ * // - Or just show as text: console.log(uri)
129
+ * console.log('Scan this QR code:', uri);
130
+ * ```
131
+ */
132
+ export async function generateConnectionUri(wcClient, network) {
133
+ try {
134
+ // Step 1: Get network configuration
135
+ const networkConfig = getNetworkConfig(network);
136
+ const chainId = `cosmos:${networkConfig.chainId}`;
137
+ // Step 2: Define optional namespaces for Akash
138
+ // This tells the wallet what permissions we need
139
+ // Using optionalNamespaces (new API) instead of deprecated requiredNamespaces
140
+ const optionalNamespaces = {
141
+ cosmos: {
142
+ chains: [chainId],
143
+ methods: [
144
+ 'cosmos_signDirect', // For transaction signing
145
+ 'cosmos_signAmino', // Legacy signing support
146
+ 'cosmos_getAccounts' // To get wallet address
147
+ ],
148
+ events: []
149
+ }
150
+ };
151
+ // Step 3: Create connection request
152
+ // This generates the URI and starts waiting for approval
153
+ const { uri, approval } = await wcClient.client.connect({
154
+ optionalNamespaces
155
+ });
156
+ // Step 4: Validate URI was generated
157
+ if (!uri) {
158
+ return {
159
+ success: false,
160
+ error: new WalletError('Failed to generate connection URI', WalletErrorCodes.URI_GENERATION_FAILED, { network })
161
+ };
162
+ }
163
+ // Step 5: Return URI and approval promise
164
+ // This matches the original kadi-deploy behavior
165
+ return {
166
+ success: true,
167
+ data: {
168
+ uri,
169
+ approval
170
+ }
171
+ };
172
+ }
173
+ catch (error) {
174
+ // Step 7: Handle connection errors
175
+ return {
176
+ success: false,
177
+ error: new WalletError(`Failed to generate connection URI: ${error}`, WalletErrorCodes.CONNECTION_FAILED, { error: String(error) })
178
+ };
179
+ }
180
+ }
181
+ /**
182
+ * Step 3: Wait for user to approve connection
183
+ *
184
+ * Polls for wallet approval with configurable timeout.
185
+ * Returns immediately when user approves or rejects.
186
+ *
187
+ * @param approval - Approval promise from step 2
188
+ * @param timeoutMs - Maximum wait time in milliseconds (default: 5 minutes)
189
+ * @returns Result with approved session or error
190
+ *
191
+ * @example
192
+ * ```typescript
193
+ * // Wait for user to scan QR and approve
194
+ * console.log('Waiting for approval...');
195
+ *
196
+ * const approvalResult = await waitForApproval(
197
+ * approval,
198
+ * 60000 // 60 second timeout
199
+ * );
200
+ *
201
+ * if (!approvalResult.success) {
202
+ * if (approvalResult.error.code === 'APPROVAL_TIMEOUT') {
203
+ * console.log('User did not approve in time');
204
+ * } else if (approvalResult.error.code === 'APPROVAL_REJECTED') {
205
+ * console.log('User rejected connection');
206
+ * }
207
+ * return;
208
+ * }
209
+ *
210
+ * const { session, address } = approvalResult.data;
211
+ * console.log(`Connected to ${address}!`);
212
+ * ```
213
+ */
214
+ export async function waitForApproval(approval, timeoutMs = 300000 // 5 minutes default
215
+ ) {
216
+ try {
217
+ // Step 1: Create timeout promise
218
+ // This races against the approval to implement timeout
219
+ const timeoutPromise = new Promise((_, reject) => {
220
+ setTimeout(() => {
221
+ reject(new Error('Connection timeout'));
222
+ }, timeoutMs);
223
+ });
224
+ // Step 2: Race approval against timeout
225
+ // Whichever resolves first wins
226
+ const session = await Promise.race([
227
+ approval(),
228
+ timeoutPromise
229
+ ]);
230
+ // Step 3: Extract account info from session
231
+ // The session contains the connected accounts
232
+ const accounts = session.namespaces.cosmos?.accounts || [];
233
+ if (accounts.length === 0) {
234
+ return {
235
+ success: false,
236
+ error: new WalletError('No accounts found in session', WalletErrorCodes.NO_ACCOUNTS, { session })
237
+ };
238
+ }
239
+ // Step 4: Parse account address and chain
240
+ // Format: "cosmos:chainid:address"
241
+ const [_namespace, chainId, address] = accounts[0].split(':');
242
+ // Validate parsed values
243
+ if (!chainId || !address) {
244
+ return {
245
+ success: false,
246
+ error: new WalletError('Invalid account format in session', WalletErrorCodes.ACCOUNT_NOT_FOUND, { account: accounts[0] })
247
+ };
248
+ }
249
+ // Step 5: Return approval result
250
+ return {
251
+ success: true,
252
+ data: {
253
+ session,
254
+ address,
255
+ chainId
256
+ }
257
+ };
258
+ }
259
+ catch (error) {
260
+ // Step 6: Handle timeout or rejection
261
+ const errorMessage = String(error);
262
+ if (errorMessage.includes('timeout')) {
263
+ return {
264
+ success: false,
265
+ error: new WalletError('Connection approval timed out', WalletErrorCodes.APPROVAL_TIMEOUT, { timeoutMs })
266
+ };
267
+ }
268
+ if (errorMessage.includes('rejected') || errorMessage.includes('cancelled')) {
269
+ return {
270
+ success: false,
271
+ error: new WalletError('User rejected connection', WalletErrorCodes.APPROVAL_REJECTED, {})
272
+ };
273
+ }
274
+ // Step 7: Handle other errors
275
+ return {
276
+ success: false,
277
+ error: new WalletError(`Approval failed: ${error}`, WalletErrorCodes.APPROVAL_FAILED, { error: errorMessage })
278
+ };
279
+ }
280
+ }
281
+ /**
282
+ * Step 4: Create complete wallet context for Akash operations
283
+ *
284
+ * Finalizes the connection by creating signers and querying account data.
285
+ * Returns a ready-to-use WalletContext for all Akash operations.
286
+ *
287
+ * @param wcClient - WalletConnect client from step 1
288
+ * @param approvalResult - Approval result from step 3
289
+ * @param network - Akash network being used
290
+ * @returns Result with complete wallet context or error
291
+ *
292
+ * @example
293
+ * ```typescript
294
+ * // Create final wallet context
295
+ * const walletResult = await createWalletContext(
296
+ * wcClient,
297
+ * approvalResult.data,
298
+ * 'mainnet'
299
+ * );
300
+ *
301
+ * if (!walletResult.success) {
302
+ * console.error('Failed to create wallet:', walletResult.error);
303
+ * return;
304
+ * }
305
+ *
306
+ * const wallet = walletResult.data;
307
+ * console.log('Wallet ready!');
308
+ * console.log('Address:', wallet.address);
309
+ * console.log('Chain:', wallet.chainId);
310
+ *
311
+ * // Now ready for Akash operations
312
+ * const deployment = await deployToAkash({ wallet, ... });
313
+ * ```
314
+ */
315
+ export async function createWalletContext(wcClient, approvalResult, network) {
316
+ try {
317
+ // Step 1: Get network configuration
318
+ const networkConfig = getNetworkConfig(network);
319
+ const chainId = networkConfig.chainId;
320
+ // Step 2: Create Keplr wallet instance via WalletConnect
321
+ // This wraps the WalletConnect session in a Keplr-compatible interface
322
+ const keplr = new KeplrWalletConnectV2(wcClient.client, approvalResult.session);
323
+ // Step 3: Get offline signer for transaction signing
324
+ // This is the main interface for signing transactions
325
+ // Note: There's a known type incompatibility between @keplr-wallet/types and @cosmjs/proto-signing
326
+ // (SignDoc.accountNumber: Long vs bigint). The runtime objects work fine - this is TypeScript only.
327
+ // We use 'as unknown as' to force the cast since TS knows the types are incompatible.
328
+ const offlineSigner = keplr.getOfflineSigner(chainId);
329
+ // Step 4: Get accounts from signer
330
+ // This should match the approved account
331
+ const accounts = await offlineSigner.getAccounts();
332
+ if (accounts.length === 0) {
333
+ return {
334
+ success: false,
335
+ error: new WalletError('No accounts available from signer', WalletErrorCodes.NO_SIGNER_ACCOUNTS, { chainId })
336
+ };
337
+ }
338
+ // Step 5: Connect to blockchain to get account details
339
+ // We need account number and sequence for transactions
340
+ const stargateClient = await StargateClient.connect(networkConfig.rpc);
341
+ let accountData;
342
+ try {
343
+ const account = await stargateClient.getAccount(accounts[0].address);
344
+ if (account) {
345
+ accountData = {
346
+ address: account.address,
347
+ pubkey: account.pubkey ? fromHex(account.pubkey.value) : null,
348
+ accountNumber: account.accountNumber,
349
+ sequence: account.sequence
350
+ };
351
+ }
352
+ }
353
+ catch (error) {
354
+ // Account might not exist on chain yet (new account)
355
+ // This is OK - account will be created with first transaction
356
+ accountData = undefined;
357
+ }
358
+ finally {
359
+ // Step 6: Always disconnect Stargate client
360
+ stargateClient.disconnect();
361
+ }
362
+ // Step 7: Create complete wallet context
363
+ const walletContext = {
364
+ address: accounts[0].address,
365
+ signer: offlineSigner,
366
+ offlineSigner: offlineSigner,
367
+ signClient: wcClient.client,
368
+ session: approvalResult.session,
369
+ chainId: chainId,
370
+ account: accountData
371
+ };
372
+ // Step 8: Return ready-to-use wallet
373
+ return {
374
+ success: true,
375
+ data: walletContext
376
+ };
377
+ }
378
+ catch (error) {
379
+ // Step 9: Handle creation errors
380
+ return {
381
+ success: false,
382
+ error: new WalletError(`Failed to create wallet context: ${error}`, WalletErrorCodes.CONTEXT_CREATION_FAILED, { error: String(error) })
383
+ };
384
+ }
385
+ }
386
+ /**
387
+ * Create wallet context from any offline signer
388
+ *
389
+ * Use this for **automated deployments** where you have direct access to a signer
390
+ * (e.g., agent wallet, CI/CD, hardware wallet, KMS) instead of interactive wallet
391
+ * connection via browser or WalletConnect.
392
+ *
393
+ * **Security Model:**
394
+ * This function accepts a **signer interface**, NOT a private key or mnemonic!
395
+ * The signer can sign transactions without exposing the underlying key.
396
+ *
397
+ * **Common Use Cases:**
398
+ * - Self-deploying agents (signer from encrypted storage)
399
+ * - CI/CD pipelines (signer from secrets manager)
400
+ * - Hardware wallets (Ledger - key never leaves device)
401
+ * - Cloud KMS (AWS/GCP - key stays in cloud)
402
+ * - Multi-signature wallets (threshold signing)
403
+ *
404
+ * @param signer - Any offline signer (must implement OfflineAminoSigner & OfflineDirectSigner)
405
+ * @param network - Akash network to connect to
406
+ * @returns Result with wallet context ready for deployments
407
+ *
408
+ * @example Agent with encrypted wallet
409
+ * ```typescript
410
+ * import { DirectSecp256k1Wallet } from '@cosmjs/proto-signing';
411
+ * import { createWalletContextFromSigner } from 'deploy-ability/akash';
412
+ *
413
+ * // Agent loads signer from secure storage (mnemonic never exposed to caller)
414
+ * const agentSigner = await myAgent.wallet.getSigner();
415
+ *
416
+ * // Create wallet context
417
+ * const walletCtx = await createWalletContextFromSigner(agentSigner, 'mainnet');
418
+ *
419
+ * if (walletCtx.success) {
420
+ * // Ready to deploy - signer will handle signing internally
421
+ * await deployToAkash({
422
+ * wallet: walletCtx.data,
423
+ * certificate: cert,
424
+ * projectRoot: './',
425
+ * profile: 'prod'
426
+ * });
427
+ * }
428
+ * ```
429
+ *
430
+ * @example CI/CD with secrets manager
431
+ * ```typescript
432
+ * // Load signer from AWS Secrets Manager / GitHub Secrets
433
+ * const mnemonic = await loadFromSecretsManager('deploy-wallet-key');
434
+ * const signer = await DirectSecp256k1Wallet.fromMnemonic(mnemonic, {
435
+ * prefix: 'akash'
436
+ * });
437
+ *
438
+ * const walletCtx = await createWalletContextFromSigner(signer, 'testnet');
439
+ * // Now deploy without any user interaction
440
+ * ```
441
+ *
442
+ * @example Hardware wallet (Ledger)
443
+ * ```typescript
444
+ * import Ledger from '@cosmjs/ledger-amino';
445
+ *
446
+ * // Connect to Ledger - key never leaves device
447
+ * const transport = await TransportWebUSB.create();
448
+ * const ledgerSigner = new Ledger(transport, {
449
+ * hdPaths: [makeCosmoshubPath(0)],
450
+ * prefix: 'akash'
451
+ * });
452
+ *
453
+ * const walletCtx = await createWalletContextFromSigner(ledgerSigner, 'mainnet');
454
+ * // Ledger will prompt for approval when signing
455
+ * ```
456
+ *
457
+ * @example Cloud KMS
458
+ * ```typescript
459
+ * // Custom signer using AWS KMS / GCP KMS
460
+ * class KmsSigner implements OfflineSigner {
461
+ * constructor(private keyId: string) {}
462
+ *
463
+ * async signDirect(address: string, signDoc: SignDoc) {
464
+ * // Sign using KMS - key never leaves cloud
465
+ * return await kms.sign(this.keyId, signDoc);
466
+ * }
467
+ * }
468
+ *
469
+ * const kmsSigner = new KmsSigner('arn:aws:kms:...');
470
+ * const walletCtx = await createWalletContextFromSigner(kmsSigner, 'mainnet');
471
+ * ```
472
+ */
473
+ export async function createWalletContextFromSigner(signer, network) {
474
+ try {
475
+ // Step 1: Get network configuration
476
+ const networkConfig = getNetworkConfig(network);
477
+ // Step 2: Get accounts from signer
478
+ // The signer provides accounts without exposing private keys
479
+ const accounts = await signer.getAccounts();
480
+ if (accounts.length === 0) {
481
+ return {
482
+ success: false,
483
+ error: new WalletError('No accounts available from signer', WalletErrorCodes.NO_SIGNER_ACCOUNTS, { network }),
484
+ };
485
+ }
486
+ const address = accounts[0].address;
487
+ // Step 3: Connect to blockchain to get account details
488
+ // We need account number and sequence for transactions
489
+ const stargateClient = await StargateClient.connect(networkConfig.rpc);
490
+ let accountData;
491
+ try {
492
+ const account = await stargateClient.getAccount(address);
493
+ if (account) {
494
+ accountData = {
495
+ address: account.address,
496
+ pubkey: account.pubkey ? fromHex(Buffer.from(account.pubkey.value).toString('hex')) : null,
497
+ accountNumber: account.accountNumber,
498
+ sequence: account.sequence,
499
+ };
500
+ }
501
+ }
502
+ finally {
503
+ // Always disconnect the query client
504
+ stargateClient.disconnect();
505
+ }
506
+ // Step 4: Create wallet context
507
+ // Note: No WalletConnect client or session - this is for direct signer usage
508
+ const walletContext = {
509
+ address,
510
+ signer,
511
+ offlineSigner: signer,
512
+ chainId: networkConfig.chainId,
513
+ account: accountData,
514
+ // signClient and session are undefined - only used for WalletConnect
515
+ };
516
+ return {
517
+ success: true,
518
+ data: walletContext,
519
+ };
520
+ }
521
+ catch (error) {
522
+ return {
523
+ success: false,
524
+ error: new WalletError(`Failed to create wallet context from signer: ${error}`, WalletErrorCodes.CONTEXT_CREATION_FAILED, { error: String(error), network }),
525
+ };
526
+ }
527
+ }
528
+ /**
529
+ * Disconnect an active WalletConnect session
530
+ *
531
+ * Cleanly disconnects from the wallet, clearing the session and cleaning up
532
+ * all internal resources (relay transport, heartbeat, event listeners).
533
+ *
534
+ * This ensures the Node.js event loop can exit by releasing all timers and
535
+ * connections. Without this cleanup, the WalletConnect client keeps the
536
+ * process alive indefinitely.
537
+ *
538
+ * Always call this when done with wallet operations to prevent hanging.
539
+ *
540
+ * Note: This only applies to WalletConnect sessions. Wallets created
541
+ * with `createWalletContextFromSigner()` don't need disconnection.
542
+ *
543
+ * @param wallet - Wallet context to disconnect
544
+ * @returns Result indicating success or error
545
+ *
546
+ * @example
547
+ * ```typescript
548
+ * // Disconnect when done
549
+ * const result = await disconnectWallet(wallet);
550
+ *
551
+ * if (result.success) {
552
+ * console.log('Wallet disconnected');
553
+ * } else {
554
+ * console.warn('Disconnect failed:', result.error);
555
+ * }
556
+ * ```
557
+ */
558
+ export async function disconnectWallet(wallet) {
559
+ try {
560
+ // Step 1: Check if WalletConnect session exists
561
+ if (!wallet.signClient || !wallet.session) {
562
+ // Not a WalletConnect wallet (maybe browser extension)
563
+ return { success: true, data: undefined };
564
+ }
565
+ try {
566
+ // Step 2: Disconnect the session
567
+ await wallet.signClient.disconnect({
568
+ topic: wallet.session.topic,
569
+ reason: {
570
+ code: 1,
571
+ message: 'User disconnected'
572
+ }
573
+ });
574
+ }
575
+ finally {
576
+ // Step 3: Clean up internal WalletConnect resources
577
+ // This is critical to allow Node.js event loop to exit
578
+ try {
579
+ // Close relay WebSocket transport
580
+ await wallet.signClient.core.relayer.transportClose();
581
+ }
582
+ catch (err) {
583
+ // Ignore transport close errors
584
+ }
585
+ try {
586
+ // Stop heartbeat timer
587
+ wallet.signClient.core.heartbeat?.stop();
588
+ }
589
+ catch (err) {
590
+ // Ignore heartbeat stop errors
591
+ }
592
+ try {
593
+ // Remove all event listeners to prevent memory leaks
594
+ // Pass undefined to remove all listeners for all events
595
+ if (wallet.signClient.core.events.removeAllListeners) {
596
+ wallet.signClient.core.events.removeAllListeners(undefined);
597
+ }
598
+ if (wallet.signClient.removeAllListeners) {
599
+ wallet.signClient.removeAllListeners(undefined);
600
+ }
601
+ }
602
+ catch (err) {
603
+ // Ignore listener removal errors
604
+ }
605
+ try {
606
+ // ================================================================
607
+ // STORAGE CLEANUP - THE RUSSIAN DOLL PROBLEM
608
+ // ================================================================
609
+ //
610
+ // WHY IS THIS NECESSARY?
611
+ // WalletConnect persists session data to disk using the "unstorage" library.
612
+ // Unstorage uses a filesystem driver that creates a "chokidar" file watcher
613
+ // to monitor the storage files for changes. File watchers keep Node.js alive
614
+ // indefinitely - the process will NEVER exit until they're explicitly closed.
615
+ //
616
+ // WHY THE WEIRD NESTING?
617
+ // WalletConnect uses a "wrapper pattern" (like Russian dolls 🪆):
618
+ //
619
+ // Layer 1: storage (wrapper with high-level API)
620
+ // └─ Has methods: getItem(), setItem(), initialize()
621
+ // └─ DOES NOT have cleanup methods!
622
+ //
623
+ // Layer 2: storage.database (queue manager)
624
+ // └─ Manages write operations with a queue
625
+ // └─ Still DOES NOT have cleanup methods!
626
+ //
627
+ // Layer 3: storage.database.database (ACTUAL DRIVER)
628
+ // └─ This is the real filesystem driver (unstorage/fs)
629
+ // └─ THIS is where unwatch() and dispose() live!
630
+ // └─ THIS is where the chokidar file watcher exists!
631
+ //
632
+ // WHY DESIGN IT THIS WAY?
633
+ // Each wrapper adds functionality:
634
+ // - Outer wrapper: Simple API for WalletConnect to use
635
+ // - Middle wrapper: Batches writes for better performance
636
+ // - Inner driver: Actually talks to the filesystem
637
+ //
638
+ // It's like a restaurant:
639
+ // - Customer (WalletConnect) → talks to waiter (storage wrapper)
640
+ // - Waiter → gives orders to kitchen manager (database queue)
641
+ // - Kitchen manager → tells chef (actual fs driver) to cook
642
+ //
643
+ // To turn off the stove (file watcher), you need to tell the chef directly,
644
+ // not the waiter! That's why we must drill down to the innermost layer.
645
+ //
646
+ // ================================================================
647
+ const storage = wallet.signClient.core?.storage;
648
+ // DRILL DOWN: storage → database → database (innermost layer)
649
+ // This is where the actual filesystem driver lives with the file watcher
650
+ const innerDb = storage?.database?.database;
651
+ if (innerDb) {
652
+ // Call unwatch() to stop the chokidar file watcher
653
+ // Without this, the file watcher keeps Node.js event loop alive forever!
654
+ if (typeof innerDb.unwatch === 'function') {
655
+ await innerDb.unwatch().catch(() => { });
656
+ }
657
+ // Call dispose() to clean up any other resources (file handles, caches, etc.)
658
+ if (typeof innerDb.dispose === 'function') {
659
+ await innerDb.dispose().catch(() => { });
660
+ }
661
+ }
662
+ }
663
+ catch (err) {
664
+ // Silently ignore storage cleanup errors during shutdown
665
+ }
666
+ }
667
+ // Step 4: Return success
668
+ return { success: true, data: undefined };
669
+ }
670
+ catch (error) {
671
+ // Step 5: Handle disconnect errors (non-fatal)
672
+ return {
673
+ success: false,
674
+ error: new WalletError(`Failed to disconnect wallet: ${error}`, WalletErrorCodes.DISCONNECT_FAILED, { error: String(error) })
675
+ };
676
+ }
677
+ }
678
+ /**
679
+ * Complete wallet connection flow (convenience function)
680
+ *
681
+ * Combines all 4 steps into a single function for simple use cases.
682
+ * For more control, use the individual step functions.
683
+ *
684
+ * @param projectId - WalletConnect project ID
685
+ * @param network - Akash network to connect to
686
+ * @param options - Optional configuration
687
+ * @returns Result with wallet context or error
688
+ *
689
+ * @example
690
+ * ```typescript
691
+ * // Simple one-call connection
692
+ * const walletResult = await connectWallet(
693
+ * 'your-project-id',
694
+ * 'mainnet',
695
+ * {
696
+ * onUriGenerated: (uri) => {
697
+ * // Display QR code
698
+ * QRCode.generate(uri);
699
+ * console.log('Scan QR code with Keplr');
700
+ * },
701
+ * timeoutMs: 60000
702
+ * }
703
+ * );
704
+ *
705
+ * if (!walletResult.success) {
706
+ * console.error('Connection failed:', walletResult.error);
707
+ * return;
708
+ * }
709
+ *
710
+ * const wallet = walletResult.data;
711
+ * console.log('Connected to:', wallet.address);
712
+ * ```
713
+ */
714
+ export async function connectWallet(projectId, network, options) {
715
+ // Step 1: Initialize WalletConnect
716
+ const clientResult = await initWalletConnect(projectId, options?.metadata);
717
+ if (!clientResult.success) {
718
+ return clientResult;
719
+ }
720
+ // Step 2: Generate connection URI
721
+ const uriResult = await generateConnectionUri(clientResult.data, network);
722
+ if (!uriResult.success) {
723
+ return uriResult;
724
+ }
725
+ // Step 3: Notify caller of URI (for QR display)
726
+ if (options?.onUriGenerated) {
727
+ options.onUriGenerated(uriResult.data.uri);
728
+ }
729
+ // Step 4: Wait for approval
730
+ const approvalResult = await waitForApproval(uriResult.data.approval, options?.timeoutMs);
731
+ if (!approvalResult.success) {
732
+ return approvalResult;
733
+ }
734
+ // Step 5: Create wallet context
735
+ return createWalletContext(clientResult.data, approvalResult.data, network);
736
+ }
737
+ /**
738
+ * Create wallet context from mnemonic (for agent-controlled wallets)
739
+ *
740
+ * ⚠️ **CRITICAL SECURITY WARNING** ⚠️
741
+ *
742
+ * This function is ONLY for scenarios where YOU control the mnemonic:
743
+ * - ✅ Your own automation (CI/CD, personal scripts)
744
+ * - ✅ Your own agent (running on infrastructure you control)
745
+ * - ✅ Custodial services YOU operate (creating wallets for your users)
746
+ *
747
+ * **NEVER use this if:**
748
+ * - ❌ Someone else's agent asks for your mnemonic
749
+ * - ❌ Third-party service requests your mnemonic
750
+ * - ❌ You don't fully control where the mnemonic is stored/used
751
+ *
752
+ * **For third-party agents/services:**
753
+ * Use `connectWallet()` with WalletConnect instead! This lets you approve
754
+ * transactions on YOUR device without exposing your mnemonic.
755
+ *
756
+ * **Security Model:**
757
+ * ```
758
+ * ┌─────────────────────────────────────────────────────────────┐
759
+ * │ WHO CONTROLS THE AGENT? │
760
+ * ├─────────────────────────────────────────────────────────────┤
761
+ * │ │
762
+ * │ YOU control it: │
763
+ * │ ✅ createWalletFromMnemonic() - You trust your own code │
764
+ * │ │
765
+ * │ SOMEONE ELSE controls it: │
766
+ * │ ✅ connectWallet() - WalletConnect for approval │
767
+ * │ ❌ createWalletFromMnemonic() - NEVER share mnemonic! │
768
+ * │ │
769
+ * └─────────────────────────────────────────────────────────────┘
770
+ * ```
771
+ *
772
+ * **Common Use Cases:**
773
+ *
774
+ * @example 1. Your own CI/CD pipeline
775
+ * ```typescript
776
+ * // Mnemonic stored in GitHub Secrets / GitLab CI Variables
777
+ * const mnemonic = process.env.DEPLOYMENT_WALLET_MNEMONIC!;
778
+ * const wallet = await createWalletFromMnemonic(mnemonic, 'mainnet');
779
+ *
780
+ * if (wallet.success) {
781
+ * // Automated deployment from CI/CD
782
+ * await deployToAkash({
783
+ * wallet: wallet.data,
784
+ * projectRoot: './',
785
+ * profile: 'production'
786
+ * });
787
+ * }
788
+ * ```
789
+ *
790
+ * @example 2. Your own agent with encrypted storage
791
+ * ```typescript
792
+ * // Agent loads its OWN mnemonic (not user's!)
793
+ * class DeploymentAgent {
794
+ * async deploy(projectConfig: Config) {
795
+ * // Agent uses its own wallet to pay for deployments
796
+ * const mnemonic = await this.secrets.getEncryptedMnemonic();
797
+ * const wallet = await createWalletFromMnemonic(mnemonic, 'mainnet');
798
+ *
799
+ * if (wallet.success) {
800
+ * // Agent deploys using its own funds
801
+ * return deployToAkash({
802
+ * wallet: wallet.data,
803
+ * ...projectConfig
804
+ * });
805
+ * }
806
+ * }
807
+ * }
808
+ * ```
809
+ *
810
+ * @example 3. Custodial wallet service (you operate the service)
811
+ * ```typescript
812
+ * // Service creates and manages wallets FOR users
813
+ * class CustodialWalletService {
814
+ * async createUserWallet(userId: string) {
815
+ * // Generate new wallet for user
816
+ * const { DirectSecp256k1HdWallet } = await import('@cosmjs/proto-signing');
817
+ * const newWallet = await DirectSecp256k1HdWallet.generate(24);
818
+ * const mnemonic = newWallet.mnemonic;
819
+ *
820
+ * // Store encrypted mnemonic in your secure database
821
+ * await this.db.storeEncryptedMnemonic(userId, mnemonic);
822
+ *
823
+ * return { userId, address: (await newWallet.getAccounts())[0].address };
824
+ * }
825
+ *
826
+ * async deployForUser(userId: string, projectConfig: Config) {
827
+ * // Load user's mnemonic from secure storage
828
+ * const mnemonic = await this.db.getDecryptedMnemonic(userId);
829
+ * const wallet = await createWalletFromMnemonic(mnemonic, 'mainnet');
830
+ *
831
+ * if (wallet.success) {
832
+ * // Deploy on user's behalf
833
+ * return deployToAkash({
834
+ * wallet: wallet.data,
835
+ * ...projectConfig
836
+ * });
837
+ * }
838
+ * }
839
+ * }
840
+ * ```
841
+ *
842
+ * @example 4. WRONG - Never do this!
843
+ * ```typescript
844
+ * // ❌ DANGEROUS - Third-party agent asking for your mnemonic!
845
+ * const thirdPartyAgent = new SomeoneElsesAgent();
846
+ *
847
+ * // ❌ DO NOT DO THIS!
848
+ * await thirdPartyAgent.deploy({
849
+ * mnemonic: myMnemonic, // ❌ Now they can steal all your funds!
850
+ * project: './my-app'
851
+ * });
852
+ *
853
+ * // ✅ DO THIS INSTEAD - Use WalletConnect!
854
+ * const wallet = await connectWallet(projectId, 'mainnet', {
855
+ * onUriGenerated: (uri) => {
856
+ * console.log('Scan QR code to approve');
857
+ * // You approve on YOUR device, agent never gets mnemonic
858
+ * }
859
+ * });
860
+ * await thirdPartyAgent.deploy({ wallet: wallet.data, ... });
861
+ * ```
862
+ *
863
+ * **Implementation Notes for Future:**
864
+ *
865
+ * This function should:
866
+ * 1. Import DirectSecp256k1HdWallet from @cosmjs/proto-signing
867
+ * 2. Create signer with proper network prefix:
868
+ * - mainnet/testnet → 'akash'
869
+ * - sandbox → 'akash'
870
+ * 3. Call createWalletContextFromSigner() with the signer
871
+ * 4. Return Result<WalletContext, WalletError>
872
+ *
873
+ * Dependencies needed:
874
+ * - @cosmjs/proto-signing (DirectSecp256k1HdWallet)
875
+ *
876
+ * Error handling:
877
+ * - Invalid mnemonic format
878
+ * - Network configuration issues
879
+ * - Account fetch failures
880
+ *
881
+ * @param mnemonic - BIP39 mnemonic phrase (12 or 24 words)
882
+ * @param network - Akash network to connect to
883
+ * @returns Result with wallet context or error
884
+ */
885
+ export async function createWalletFromMnemonic(_mnemonic, network) {
886
+ // TODO: Implement mnemonic → wallet conversion
887
+ //
888
+ // Implementation plan:
889
+ //
890
+ // 1. Validate mnemonic format (should be 12 or 24 words)
891
+ // - Split by whitespace and count words
892
+ // - Return error if invalid length
893
+ //
894
+ // 2. Import DirectSecp256k1HdWallet from @cosmjs/proto-signing
895
+ // - This is the standard CosmJS wallet for Cosmos chains
896
+ // - Handles BIP39 mnemonic → keypair derivation
897
+ //
898
+ // 3. Create signer with Akash address prefix
899
+ // const signer = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, {
900
+ // prefix: 'akash' // All Akash networks use 'akash' prefix
901
+ // });
902
+ //
903
+ // 4. Delegate to existing createWalletContextFromSigner()
904
+ // return createWalletContextFromSigner(signer, network);
905
+ //
906
+ // Error cases to handle:
907
+ // - Invalid mnemonic (wrong word count, invalid words)
908
+ // - Network configuration issues (passed through from createWalletContextFromSigner)
909
+ // - Account fetch failures (passed through from createWalletContextFromSigner)
910
+ //
911
+ // Example implementation:
912
+ //
913
+ // try {
914
+ // // Validate mnemonic word count
915
+ // const words = mnemonic.trim().split(/\s+/);
916
+ // if (![12, 15, 18, 21, 24].includes(words.length)) {
917
+ // return {
918
+ // success: false,
919
+ // error: new WalletError(
920
+ // `Invalid mnemonic: expected 12, 15, 18, 21, or 24 words, got ${words.length}`,
921
+ // WalletErrorCodes.INVALID_MNEMONIC,
922
+ // { wordCount: words.length }
923
+ // ),
924
+ // };
925
+ // }
926
+ //
927
+ // // Import CosmJS wallet
928
+ // const { DirectSecp256k1HdWallet } = await import('@cosmjs/proto-signing');
929
+ //
930
+ // // Create signer from mnemonic
931
+ // const signer = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, {
932
+ // prefix: 'akash'
933
+ // });
934
+ //
935
+ // // Delegate to existing function
936
+ // return createWalletContextFromSigner(signer, network);
937
+ // } catch (error) {
938
+ // return {
939
+ // success: false,
940
+ // error: new WalletError(
941
+ // `Failed to create wallet from mnemonic: ${error}`,
942
+ // WalletErrorCodes.MNEMONIC_CREATION_FAILED,
943
+ // { error: String(error), network }
944
+ // ),
945
+ // };
946
+ // }
947
+ // Temporary implementation - will be replaced with above
948
+ return {
949
+ success: false,
950
+ error: new WalletError('createWalletFromMnemonic() not yet implemented - see TODO in function body', WalletErrorCodes.NOT_IMPLEMENTED, { network }),
951
+ };
952
+ }
953
+ //# sourceMappingURL=wallet-manager.js.map