@zyfai/sdk 0.1.0

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.
package/README.md ADDED
@@ -0,0 +1,722 @@
1
+ # ZyFAI SDK
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@zyfai/sdk.svg)](https://www.npmjs.com/package/@zyfai/sdk)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ TypeScript SDK for interacting with the ZyFAI Yield Optimization Engine. This SDK provides easy-to-use methods for deploying Safe smart wallets, managing DeFi positions, and optimizing yield across multiple protocols.
7
+
8
+ ## Features
9
+
10
+ - **Safe Smart Wallet Deployment**: Deploy Safe wallets with deterministic addresses
11
+ - **Flexible Authentication**: Support for private keys and modern wallet providers
12
+ - **Multi-Chain Support**: Works on Arbitrum, Base, and Plasma
13
+ - **Yield Optimization**: Access to multiple DeFi protocols and strategies
14
+ - **Position Tracking**: Monitor and manage your DeFi positions across chains
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @zyfai/sdk viem
20
+ # or
21
+ yarn add @zyfai/sdk viem
22
+ # or
23
+ pnpm add @zyfai/sdk viem
24
+ ```
25
+
26
+ ## Prerequisites
27
+
28
+ 1. **Execution API Key**: API key for the Execution API (Safe deployment, transactions, session keys)
29
+ 2. **Data API Key** (optional): API key for the Data API (earnings, opportunities, analytics). If not provided, uses the Execution API key.
30
+ 3. **Bundler API Key**: Required for Safe deployment. Get it from:
31
+ - [Pimlico](https://www.pimlico.io/) (Recommended)
32
+
33
+ **Get your API keys from [ZyFAI Dashboard](https://app.zyf.ai)**
34
+
35
+ ## Quick Start
36
+
37
+ ### Initialize the SDK
38
+
39
+ ```typescript
40
+ import { ZyfaiSDK } from "@zyfai/sdk";
41
+
42
+ const sdk = new ZyfaiSDK({
43
+ apiKey: "your-execution-api-key", // Execution API (transactions, Safe deployment)
44
+ dataApiKey: "your-data-api-key", // Data API (analytics, earnings, opportunities)
45
+ bundlerApiKey: "your-bundler-api-key", // Required for Safe deployment
46
+ environment: "production", // or 'staging' (default: 'production')
47
+ });
48
+ ```
49
+
50
+ **Configuration Options:**
51
+
52
+ | Option | Required | Description |
53
+ | --------------- | -------- | ----------------------------------------------------------------------------------------------- |
54
+ | `apiKey` | Yes | API key for Execution API (Safe deployment, transactions, session keys) |
55
+ | `dataApiKey` | No | API key for Data API (earnings, opportunities, analytics). Defaults to `apiKey` if not provided |
56
+ | `bundlerApiKey` | No\* | Pimlico API key for Safe deployment (\*required for `deploySafe`) |
57
+ | `environment` | No | `"production"` or `"staging"` (default: `"production"`) |
58
+
59
+ **API Endpoints by Environment:**
60
+
61
+ | Environment | Execution API | Data API |
62
+ | ------------ | ---------------------------- | --------------------------------- |
63
+ | `production` | `https://api.zyf.ai` | `https://defi-api.zyf.ai` |
64
+ | `staging` | `https://staging-api.zyf.ai` | `https://staging-defi-api.zyf.ai` |
65
+
66
+ ### Connect Account
67
+
68
+ The SDK accepts either a private key or a modern wallet provider:
69
+
70
+ ```typescript
71
+ // Option 1: With private key (chainId required)
72
+ await sdk.connectAccount("0x...", 42161);
73
+
74
+ // Option 2: With wallet provider (chainId optional - uses provider's chain)
75
+ const provider = await connector.getProvider();
76
+ await sdk.connectAccount(provider); // SDK detects chain from provider
77
+
78
+ // Option 3: With EIP-1193 provider
79
+ const provider = window.ethereum; // Client passes this from their frontend
80
+ await sdk.connectAccount(provider); // Automatically uses provider's current chain
81
+
82
+ // Now call methods with explicit user addresses
83
+ const userAddress = "0xUser...";
84
+ await sdk.deploySafe(userAddress, 42161);
85
+ ```
86
+
87
+ **Note:** When using a wallet provider, the SDK automatically detects the chain from the provider. You can optionally specify `chainId` to override.
88
+
89
+ ## Core Features
90
+
91
+ ### 1. Deploy Safe Smart Wallet
92
+
93
+ Deploy a Safe smart wallet:
94
+
95
+ ```typescript
96
+ const userAddress = "0xUser..."; // User's EOA address
97
+
98
+ // Get the deterministic Safe address (before deployment)
99
+ const walletInfo = await sdk.getSmartWalletAddress(userAddress, 42161);
100
+ console.log("Safe Address:", walletInfo.address);
101
+ console.log("Is Deployed:", walletInfo.isDeployed);
102
+
103
+ // Deploy the Safe
104
+ const result = await sdk.deploySafe(userAddress, 42161);
105
+
106
+ if (result.success) {
107
+ console.log("Safe Address:", result.safeAddress);
108
+ console.log("Status:", result.status); // 'deployed' | 'failed'
109
+ console.log("Transaction Hash:", result.txHash);
110
+ }
111
+ ```
112
+
113
+ ### 2. Multi-Chain Support
114
+
115
+ The SDK supports the following chains:
116
+
117
+ | Chain | Chain ID | Status |
118
+ | -------- | -------- | ------ |
119
+ | Arbitrum | 42161 | ✅ |
120
+ | Base | 8453 | ✅ |
121
+ | Plasma | 9745 | ✅ |
122
+
123
+ Example with different chains:
124
+
125
+ ```typescript
126
+ import { getSupportedChainIds, isSupportedChain } from "@zyfai/sdk";
127
+
128
+ // Get all supported chains
129
+ const chains = getSupportedChainIds();
130
+ console.log("Supported chains:", chains);
131
+
132
+ // Check if a chain is supported
133
+ if (isSupportedChain(42161)) {
134
+ const userAddress = "0xUser...";
135
+ const result = await sdk.deploySafe(userAddress, 42161); // Arbitrum
136
+ }
137
+ ```
138
+
139
+ ## API Reference
140
+
141
+ ### `ZyfaiSDK`
142
+
143
+ #### Constructor
144
+
145
+ ```typescript
146
+ new ZyfaiSDK(config: SDKConfig | string)
147
+ ```
148
+
149
+ **Parameters:**
150
+
151
+ - `config`: Configuration object or API key string
152
+ - `apiKey` (string): Your ZyFAI API key
153
+ - `environment` ('production' | 'staging', optional): API environment (default: 'production')
154
+ - `bundlerApiKey` (string, optional): Bundler API key for Safe deployment (required for deploySafe)
155
+
156
+ #### Methods
157
+
158
+ ##### `connectAccount(account: string | any, chainId?: SupportedChainId): Promise<Address>`
159
+
160
+ Connect account for signing transactions. Accepts either a private key string or a modern wallet provider.
161
+
162
+ **Parameters:**
163
+
164
+ - `account`: Private key string or wallet provider object (EIP-1193 provider, viem WalletClient, etc.)
165
+ - `chainId`: Target chain ID
166
+ - **Required** for private key
167
+ - **Optional** for wallet providers (auto-detects from provider)
168
+ - Default: 42161 (Arbitrum)
169
+
170
+ **Returns:** Connected wallet address
171
+
172
+ **Examples:**
173
+
174
+ ```typescript
175
+ // With private key (chainId required)
176
+ await sdk.connectAccount("0x...", 42161);
177
+
178
+ // With wallet provider (chainId optional)
179
+ const provider = await connector.getProvider();
180
+ await sdk.connectAccount(provider); // Uses provider's current chain
181
+ ```
182
+
183
+ ##### `getSmartWalletAddress(userAddress: string, chainId: SupportedChainId): Promise<SmartWalletResponse>`
184
+
185
+ Get the Smart Wallet (Safe) address for a user.
186
+
187
+ **Parameters:**
188
+
189
+ - `userAddress`: User's EOA address
190
+ - `chainId`: Target chain ID
191
+
192
+ **Returns:**
193
+
194
+ ```typescript
195
+ {
196
+ address: Address; // Safe address
197
+ isDeployed: boolean; // Whether the Safe is deployed
198
+ }
199
+ ```
200
+
201
+ ##### `deploySafe(userAddress: string, chainId: SupportedChainId): Promise<DeploySafeResponse>`
202
+
203
+ Deploy a Safe smart wallet for a user.
204
+
205
+ **Parameters:**
206
+
207
+ - `userAddress`: User's EOA address
208
+ - `chainId`: Target chain ID
209
+
210
+ **Returns:**
211
+
212
+ ```typescript
213
+ {
214
+ success: boolean;
215
+ safeAddress: Address;
216
+ txHash: string;
217
+ status: "deployed" | "failed";
218
+ }
219
+ ```
220
+
221
+ ### 3. Session Keys
222
+
223
+ Session keys enable delegated transaction execution without exposing the main private key.
224
+
225
+ #### Simple Usage (Recommended)
226
+
227
+ The SDK automatically fetches optimal session configuration from ZyFAI API:
228
+
229
+ ```typescript
230
+ // SDK automatically:
231
+ // 1. Authenticates via SIWE (creates user record if needed)
232
+ // 2. Calculates the deterministic Safe address
233
+ // 3. Resolves the userId via /users/by-smart-wallet
234
+ // 4. Retrieves personalized config via /session-keys/config
235
+ // 5. Signs the session key
236
+ // 6. Calls /session-keys/add so the session becomes active immediately
237
+
238
+ const result = await sdk.createSessionKey(userAddress, 42161);
239
+
240
+ console.log("Session created:", result.signature);
241
+ console.log("Safe address:", result.sessionKeyAddress);
242
+ console.log("User ID:", result.userId);
243
+ console.log("Activation ID:", result.sessionActivation?.id);
244
+ ```
245
+
246
+ **Important**:
247
+
248
+ - `createSessionKey` requires SIWE authentication (prompts wallet signature on first call)
249
+ - The user record must have `smartWallet` and `chainId` set (automatically handled after calling `deploySafe` or `updateUserProfile`)
250
+ - The SDK now auto-calls `/users/by-smart-wallet`, `/session-keys/config`, and `/session-keys/add`, so the returned payload already includes the `userId` and the activation record (`sessionActivation`)—no additional API calls are required on your side.
251
+
252
+ ### 4. Deposit Funds
253
+
254
+ Transfer tokens to your Safe smart wallet:
255
+
256
+ ```typescript
257
+ // Deposit 100 USDC (6 decimals) to Safe on Arbitrum
258
+ const result = await sdk.depositFunds(
259
+ userAddress,
260
+ 42161, // Chain ID
261
+ "0xaf88d065e77c8cc2239327c5edb3a432268e5831", // USDC on Arbitrum
262
+ "100000000" // Amount: 100 USDC = 100 * 10^6
263
+ );
264
+
265
+ if (result.success) {
266
+ console.log("Deposit successful!");
267
+ console.log("Transaction Hash:", result.txHash);
268
+ }
269
+ ```
270
+
271
+ **Note:** Amount must be in least decimal units. For USDC (6 decimals): 1 USDC = 1000000
272
+ The SDK automatically authenticates via SIWE before logging the deposit with ZyFAI's API, so no extra steps are required on your end once the transfer confirms.
273
+
274
+ ### 5. Withdraw Funds
275
+
276
+ Withdraw funds from your Safe:
277
+
278
+ ```typescript
279
+ // Full withdrawal
280
+ const result = await sdk.withdrawFunds(userAddress, 42161);
281
+
282
+ // Partial withdrawal of 50 USDC (6 decimals)
283
+ const result = await sdk.withdrawFunds(
284
+ userAddress,
285
+ 42161,
286
+ "50000000", // Amount: 50 USDC = 50 * 10^6
287
+ "0xReceiverAddress" // Optional: receiver address
288
+ );
289
+
290
+ if (result.success) {
291
+ console.log("Withdrawal successful!");
292
+ console.log("Transaction Hash:", result.txHash);
293
+ }
294
+ ```
295
+
296
+ **Note:** Amount must be in least decimal units. For USDC (6 decimals): 1 USDC = 1000000
297
+ The SDK authenticates via SIWE before calling the withdrawal endpoints (`/users/withdraw` or `/users/partial-withdraw`) so you don't need to manage tokens manually.
298
+
299
+ ### 6. Get Available Protocols
300
+
301
+ Retrieve all available DeFi protocols and pools for a specific chain:
302
+
303
+ ```typescript
304
+ const protocols = await sdk.getAvailableProtocols(42161);
305
+
306
+ console.log(`Found ${protocols.protocols.length} protocols`);
307
+ protocols.protocols.forEach((protocol) => {
308
+ console.log(`${protocol.name} (${protocol.type})`);
309
+ console.log(`Chains: ${protocol.chains.join(", ")}`);
310
+ console.log(`Strategies: ${protocol.strategies?.join(", ") ?? "n/a"}`);
311
+ console.log(`Website: ${protocol.website ?? "n/a"}`);
312
+ console.log(`Pools: ${protocol.pools?.length ?? 0}`);
313
+ });
314
+ ```
315
+
316
+ **Note**: This endpoint fetches protocols from `/api/v1/protocols?chainId={chainId}` and returns additional metadata such as `type`, `strategies`, `chains`, `website`, and an optional `imageUrl`.
317
+
318
+ ### 7. Monitor Positions
319
+
320
+ Track all active DeFi positions for a user:
321
+
322
+ ```typescript
323
+ const positions = await sdk.getPositions(userAddress);
324
+ positions.positions.forEach((bundle) => {
325
+ console.log(`Chain: ${bundle.chain}, Strategy: ${bundle.strategy}`);
326
+ bundle.positions.forEach((slot) => {
327
+ console.log(`Token: ${slot.token_symbol}, Pool: ${slot.pool}`);
328
+ console.log(`Underlying Amount: ${slot.underlyingAmount}`);
329
+ });
330
+ });
331
+ ```
332
+
333
+ **Note**: This endpoint uses `/api/v1/data/position?walletAddress={address}` (Smart wallet address) and returns bundles with nested slot data. Use each slot's `underlyingAmount` for the canonical token balance.
334
+
335
+ ### 8. Analytics & Data Endpoints
336
+
337
+ The SDK provides access to various analytics and data endpoints:
338
+
339
+ #### Get User Details
340
+
341
+ ```typescript
342
+ const user = await sdk.getUserDetails();
343
+ console.log("Smart Wallet:", user.user.smartWallet);
344
+ console.log("Active Chains:", user.user.chains);
345
+ ```
346
+
347
+ #### Get TVL & Volume
348
+
349
+ ```typescript
350
+ const tvl = await sdk.getTVL();
351
+ console.log("Total TVL:", tvl.totalTvl);
352
+
353
+ const volume = await sdk.getVolume();
354
+ console.log("Total Volume:", volume.volumeInUSD);
355
+ ```
356
+
357
+ #### Get Active Wallets
358
+
359
+ ```typescript
360
+ const wallets = await sdk.getActiveWallets(8453); // Base chain
361
+ console.log("Active wallet count:", wallets.count);
362
+ ```
363
+
364
+ #### Get Smart Wallets by EOA
365
+
366
+ ```typescript
367
+ const result = await sdk.getSmartWalletsByEOA("0xYourEOA...");
368
+ console.log("Smart wallets:", result.smartWallets);
369
+ ```
370
+
371
+ #### Get Transaction History
372
+
373
+ ```typescript
374
+ const history = await sdk.getHistory(walletAddress, 8453, {
375
+ limit: 50,
376
+ fromDate: "2024-01-01",
377
+ });
378
+ history.data.forEach((tx) => console.log(tx.type, tx.amount));
379
+ ```
380
+
381
+ ### 9. Earnings & Performance
382
+
383
+ #### Get Onchain Earnings
384
+
385
+ ```typescript
386
+ const earnings = await sdk.getOnchainEarnings(walletAddress);
387
+ console.log("Total Earnings:", earnings.data.totalEarnings);
388
+ console.log("Current Earnings:", earnings.data.currentEarnings);
389
+ console.log("Lifetime Earnings:", earnings.data.lifetimeEarnings);
390
+ ```
391
+
392
+ #### Calculate Onchain Earnings (Refresh)
393
+
394
+ ```typescript
395
+ const updated = await sdk.calculateOnchainEarnings(walletAddress);
396
+ console.log("Updated earnings:", updated.data.totalEarnings);
397
+ ```
398
+
399
+ #### Get Daily Earnings
400
+
401
+ ```typescript
402
+ const daily = await sdk.getDailyEarnings(
403
+ walletAddress,
404
+ "2024-01-01",
405
+ "2024-01-31"
406
+ );
407
+ daily.data.forEach((d) => console.log(d.date, d.earnings));
408
+ ```
409
+
410
+ #### Get Daily APY History
411
+
412
+ ```typescript
413
+ const apyHistory = await sdk.getDailyApyHistory(walletAddress, "30D");
414
+ console.log("Average Weighted APY:", apyHistory.averageWeightedApy);
415
+ ```
416
+
417
+ ### 10. Opportunities & Strategies
418
+
419
+ #### Get Safe Opportunities (Low Risk)
420
+
421
+ ```typescript
422
+ const safeOpps = await sdk.getSafeOpportunities(8453);
423
+ safeOpps.data.forEach((o) => {
424
+ console.log(`${o.protocolName} - ${o.poolName}: ${o.apy}% APY`);
425
+ });
426
+ ```
427
+
428
+ #### Get Degen Strategies (High Risk)
429
+
430
+ ```typescript
431
+ const degenStrats = await sdk.getDegenStrategies(8453);
432
+ degenStrats.data.forEach((s) => {
433
+ console.log(`${s.protocolName} - ${s.poolName}: ${s.apy}% APY`);
434
+ });
435
+ ```
436
+
437
+ ### 11. Rebalancing
438
+
439
+ #### Get Rebalance Info
440
+
441
+ ```typescript
442
+ // Get same-chain rebalances
443
+ const rebalances = await sdk.getRebalanceInfo(false);
444
+ console.log("Rebalance events:", rebalances.count);
445
+
446
+ // Get cross-chain rebalances
447
+ const crossChain = await sdk.getRebalanceInfo(true);
448
+ ```
449
+
450
+ #### Get Rebalance Frequency
451
+
452
+ ```typescript
453
+ const frequency = await sdk.getRebalanceFrequency(walletAddress);
454
+ console.log("Tier:", frequency.tier);
455
+ console.log("Max rebalances/day:", frequency.frequency);
456
+ ```
457
+
458
+ ### 12. Portfolio (Premium)
459
+
460
+ #### Get Debank Portfolio (Multi-chain)
461
+
462
+ ```typescript
463
+ const portfolio = await sdk.getDebankPortfolio(walletAddress);
464
+ console.log("Total Value:", portfolio.totalValueUsd);
465
+ Object.entries(portfolio.chains).forEach(([chain, data]) => {
466
+ console.log(`${chain}: $${data.totalValueUsd}`);
467
+ });
468
+ ```
469
+
470
+ **Note**: The Debank portfolio endpoint is a premium feature and may require additional authorization.
471
+
472
+ ## Examples
473
+
474
+ All examples are available in the `examples/` directory:
475
+
476
+ ### Core Features
477
+
478
+ 1. **`end-to-end.ts`** - Complete workflow demonstrating all SDK features
479
+ 2. **`basic-usage.ts`** - Simple Safe deployment workflow
480
+ 3. **`create-session-key.ts`** - Session key creation + registration
481
+ 4. **`deposit.ts`** - Deposit funds to Safe
482
+ 5. **`withdraw.ts`** - Withdraw funds from Safe
483
+ 6. **`deposit-withdraw.ts`** - Combined fund management examples
484
+
485
+ ### Data Retrieval
486
+
487
+ 7. **`get-protocols.ts`** - Fetch available protocols for a chain
488
+ 8. **`get-positions.ts`** - Get active positions for a wallet
489
+ 9. **`get-user-details.ts`** - Get authenticated user details
490
+ 10. **`get-tvl-volume.ts`** - Get TVL and trading volume
491
+ 11. **`get-active-wallets.ts`** - Get active wallets by chain
492
+ 12. **`get-smart-wallets-by-eoa.ts`** - Get smart wallets by EOA
493
+ 13. **`get-first-topup.ts`** - Get first deposit information
494
+ 14. **`get-history.ts`** - Get transaction history
495
+
496
+ ### Analytics & Earnings
497
+
498
+ 15. **`get-onchain-earnings.ts`** - Get/calculate onchain earnings
499
+ 16. **`get-daily-earnings.ts`** - Get daily earnings breakdown
500
+ 17. **`get-apy-history.ts`** - Get daily APY history with weighted averages
501
+
502
+ ### Opportunities & Rebalancing
503
+
504
+ 18. **`get-opportunities.ts`** - Get safe and degen yield opportunities
505
+ 19. **`get-rebalance-info.ts`** - Get rebalance events and frequency tier
506
+
507
+ ### Premium Features
508
+
509
+ 20. **`get-debank-portfolio.ts`** - Get Debank multi-chain portfolio
510
+
511
+ ### Quick Start: Run the End-to-End Example
512
+
513
+ ```bash
514
+ # 1. Set up environment variables
515
+ cp .env.example .env
516
+ # Edit .env with your API keys
517
+
518
+ # 2. Build the SDK
519
+ pnpm install
520
+ pnpm build
521
+
522
+ # 3. Run the complete workflow
523
+ pnpm tsx examples/end-to-end.ts
524
+ ```
525
+
526
+ ## Complete Examples
527
+
528
+ ### Example 1: Deploy Safe on Arbitrum
529
+
530
+ ```typescript
531
+ import { ZyfaiSDK } from "@zyfai/sdk";
532
+
533
+ async function main() {
534
+ const sdk = new ZyfaiSDK({
535
+ apiKey: process.env.ZYFAI_API_KEY!,
536
+ bundlerApiKey: process.env.BUNDLER_API_KEY!,
537
+ });
538
+
539
+ // Connect account (for signing)
540
+ await sdk.connectAccount(process.env.PRIVATE_KEY!, 42161);
541
+
542
+ const userAddress = "0xUser..."; // User's EOA address
543
+
544
+ // Check if Safe already exists
545
+ const walletInfo = await sdk.getSmartWalletAddress(userAddress, 42161);
546
+
547
+ if (walletInfo.isDeployed) {
548
+ console.log("Safe already deployed at:", walletInfo.address);
549
+ return;
550
+ }
551
+
552
+ // Deploy Safe
553
+ const result = await sdk.deploySafe(userAddress, 42161);
554
+
555
+ if (result.success) {
556
+ console.log("✅ Successfully deployed Safe");
557
+ console.log("Address:", result.safeAddress);
558
+ console.log("Tx Hash:", result.txHash);
559
+ }
560
+ }
561
+
562
+ main();
563
+ ```
564
+
565
+ ### Example 2: Browser Integration with React
566
+
567
+ ```typescript
568
+ import { ZyfaiSDK } from "@zyfai/sdk";
569
+ import { useState } from "react";
570
+
571
+ function SafeDeployment() {
572
+ const [sdk] = useState(
573
+ () =>
574
+ new ZyfaiSDK({
575
+ apiKey: process.env.ZYFAI_API_KEY!,
576
+ bundlerApiKey: process.env.BUNDLER_API_KEY!,
577
+ })
578
+ );
579
+
580
+ const [userAddress, setUserAddress] = useState<string>("");
581
+ const [safeAddress, setSafeAddress] = useState<string>("");
582
+ const [isDeploying, setIsDeploying] = useState(false);
583
+
584
+ const handleConnect = async (walletProvider: any) => {
585
+ try {
586
+ // Client passes the wallet provider from their frontend
587
+ // e.g., from wagmi: const provider = await connector.getProvider();
588
+ const address = await sdk.connectAccount(walletProvider); // chainId auto-detected
589
+ setUserAddress(address);
590
+ console.log("Connected:", address);
591
+
592
+ // Get Safe address for this user
593
+ const walletInfo = await sdk.getSmartWalletAddress(address, 42161);
594
+ setSafeAddress(walletInfo.address);
595
+ } catch (error) {
596
+ console.error("Connection failed:", error);
597
+ }
598
+ };
599
+
600
+ const handleDeploy = async () => {
601
+ if (!userAddress) return;
602
+
603
+ setIsDeploying(true);
604
+ try {
605
+ const result = await sdk.deploySafe(userAddress, 42161);
606
+ if (result.success) {
607
+ alert(`Safe deployed at ${result.safeAddress}`);
608
+ }
609
+ } catch (error) {
610
+ console.error("Deployment failed:", error);
611
+ } finally {
612
+ setIsDeploying(false);
613
+ }
614
+ };
615
+
616
+ return (
617
+ <div>
618
+ <button
619
+ onClick={async () => {
620
+ // Client gets provider from their wallet connection library
621
+ const provider = window.ethereum; // or from wagmi, web3-react, etc.
622
+ await handleConnect(provider);
623
+ }}
624
+ >
625
+ Connect Wallet
626
+ </button>
627
+ {userAddress && (
628
+ <>
629
+ <p>Connected: {userAddress}</p>
630
+ <p>Your Safe: {safeAddress}</p>
631
+ <button onClick={handleDeploy} disabled={isDeploying}>
632
+ {isDeploying ? "Deploying..." : "Deploy Safe"}
633
+ </button>
634
+ </>
635
+ )}
636
+ </div>
637
+ );
638
+ }
639
+ ```
640
+
641
+ **Important Note:** The SDK doesn't connect to wallets directly. The client integrating the SDK should handle wallet connection on their frontend and pass the provider to `connectAccount()`.
642
+
643
+ ## Architecture
644
+
645
+ The SDK is built on top of:
646
+
647
+ - **Viem**: Low-level Ethereum interactions
648
+ - **Axios**: HTTP client for API communication
649
+
650
+ ### How Safe Deployment Works
651
+
652
+ 1. **Deterministic Address Generation**: Safe addresses are generated deterministically using CREATE2
653
+ 2. **Explicit Parameters**: All methods take explicit user addresses - the connected account is only used for signing
654
+ 3. **Multi-User Support**: One SDK instance can manage multiple users
655
+ 4. **Backend-Friendly**: Perfect for services managing Safe wallets for multiple users
656
+
657
+ ## Error Handling
658
+
659
+ ```typescript
660
+ try {
661
+ const userAddress = "0xUser...";
662
+ const result = await sdk.deploySafe(userAddress, 42161);
663
+ if (!result.success) {
664
+ console.error("Deployment failed:", result.status);
665
+ }
666
+ } catch (error) {
667
+ if (error instanceof Error) {
668
+ console.error("Error:", error.message);
669
+ }
670
+ }
671
+ ```
672
+
673
+ ## Best Practices
674
+
675
+ 1. **Store API Keys Securely**: Never commit API keys to version control
676
+ 2. **Use Environment Variables**: Store keys in `.env` files
677
+ 3. **Check Deployment Status**: Always check if Safe is already deployed before deploying
678
+ 4. **Handle Errors Gracefully**: Implement proper error handling for all SDK methods
679
+ 5. **Validate Chain IDs**: Ensure you're using supported chains (Arbitrum, Base, Plasma)
680
+ 6. **Use Explicit Parameters**: Always pass explicit `userAddress` and `chainId` to methods
681
+
682
+ ## Environment Variables
683
+
684
+ For running the examples, set up the following environment variables:
685
+
686
+ ```bash
687
+ # Required: Execution API key (Safe deployment, transactions, session keys)
688
+ ZYFAI_API_KEY=your-execution-api-key
689
+
690
+ # Optional: Data API key (earnings, opportunities, analytics)
691
+ # Falls back to ZYFAI_API_KEY if not provided
692
+ ZYFAI_DATA_API_KEY=your-data-api-key
693
+
694
+ # Required for Safe deployment: Bundler API key (e.g., Pimlico)
695
+ BUNDLER_API_KEY=your-pimlico-api-key
696
+
697
+ # Required for examples: Private key for signing transactions
698
+ # WARNING: Never commit your private key to version control!
699
+ PRIVATE_KEY=0x...
700
+
701
+ # Optional: Chain ID (default: 8453 for Base)
702
+ # Supported: 42161 (Arbitrum), 8453 (Base), 9745 (Plasma)
703
+ CHAIN_ID=8453
704
+ ```
705
+
706
+ ## Troubleshooting
707
+
708
+ ### "No account connected" Error
709
+
710
+ Make sure to call `connectAccount()` before calling other methods that require signing.
711
+
712
+ ### "Unsupported chain" Error
713
+
714
+ Check that the chain ID is in the supported chains list: Arbitrum (42161), Base (8453), or Plasma (9745).
715
+
716
+ ## Contributing
717
+
718
+ Contributions are welcome! Please open an issue or submit a pull request.
719
+
720
+ ## License
721
+
722
+ MIT