@mycelium-sdk/core 0.1.0 → 1.0.0-alpha.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.
package/dist/index.js CHANGED
@@ -348,9 +348,9 @@ var DefaultSmartWallet = class extends SmartWallet {
348
348
  * @param amount Human-readable amount string
349
349
  * @returns Transaction result for the deposit
350
350
  */
351
- async earn(amount) {
351
+ async earn(vaultInfo, amount) {
352
352
  this.chainManager.getSupportedChain();
353
- const depositTransactionResult = this.protocolProvider.deposit(amount, this);
353
+ const depositTransactionResult = this.protocolProvider.deposit(vaultInfo, amount, this);
354
354
  return depositTransactionResult;
355
355
  }
356
356
  /**
@@ -361,13 +361,9 @@ var DefaultSmartWallet = class extends SmartWallet {
361
361
  * @category Earn
362
362
  * @returns Vault balance or `null` if nothing deposited
363
363
  */
364
- async getEarnBalance() {
365
- const depositedVault = await this.protocolProvider.fetchDepositedVaults(this);
366
- if (!depositedVault) {
367
- return null;
368
- }
364
+ async getEarnBalances() {
369
365
  const userAddress = await this.getAddress();
370
- return this.protocolProvider.getBalance(depositedVault, userAddress);
366
+ return this.protocolProvider.getBalances(userAddress);
371
367
  }
372
368
  /**
373
369
  * Withdraws from the selected protocol’s vault
@@ -378,8 +374,8 @@ var DefaultSmartWallet = class extends SmartWallet {
378
374
  * @throws Error if the withdrawal fails
379
375
  * @throws Error a user didn't deposit anything
380
376
  */
381
- async withdraw(amount) {
382
- const withdrawTransactionResult = await this.protocolProvider.withdraw(amount, this);
377
+ async withdraw(vaultInfo, amount) {
378
+ const withdrawTransactionResult = await this.protocolProvider.withdraw(vaultInfo, amount, this);
383
379
  return withdrawTransactionResult;
384
380
  }
385
381
  /**
@@ -416,7 +412,7 @@ var DefaultSmartWallet = class extends SmartWallet {
416
412
  return hash;
417
413
  } catch (error) {
418
414
  throw new Error(
419
- `Failed to send transaction: ${error instanceof Error ? error.message : "Unknown error"}`
415
+ `Failed to send transaction: ${error instanceof Error ? error.message.toString().slice(0, 100) : "Unknown error"}`
420
416
  );
421
417
  }
422
418
  }
@@ -461,7 +457,7 @@ var DefaultSmartWallet = class extends SmartWallet {
461
457
  * Funds the smart wallet with the specified amount of the specified token via Coinbase CDP on-ramp service
462
458
  *
463
459
  * @public
464
- * @category Ramp
460
+ * @category Funding
465
461
  *
466
462
  * @remarks
467
463
  * If Coinbase CDP is not initialized, the method will throw an error. For more details, visit @see {@link https://docs.cdp.coinbase.com/api-reference/v2/rest-api/onramp/create-an-onramp-session}
@@ -499,7 +495,7 @@ var DefaultSmartWallet = class extends SmartWallet {
499
495
  * Cashout token from smart wallet to fiat currency via Coinbase CDP off-ramp service
500
496
  *
501
497
  * @public
502
- * @category Ramp
498
+ * @category Funding
503
499
  *
504
500
  * @remarks
505
501
  * If Coinbase CDP is not initialized, the method will throw an error. For more details, visit @see {@link https://docs.cdp.coinbase.com/api-reference/rest-api/onramp-offramp/create-sell-quote}
@@ -575,6 +571,42 @@ var DefaultSmartWallet = class extends SmartWallet {
575
571
  }
576
572
  };
577
573
 
574
+ // src/ramp/FundingNamespace.ts
575
+ var FundingNamespace = class {
576
+ constructor(coinbaseCDP) {
577
+ this.coinbaseCDP = null;
578
+ if (!coinbaseCDP) {
579
+ throw new Error(
580
+ "Coinbase CDP is not initialized. Please, provide the configuration in the SDK initialization"
581
+ );
582
+ }
583
+ this.coinbaseCDP = coinbaseCDP;
584
+ }
585
+ /**
586
+ * Return all supported countries and payment methods for on-ramp by Coinbase CDP
587
+ * @public
588
+ * @category Funding
589
+ *
590
+ * @returns @see {@link RampConfigResponse} with supported countries and payment methods for top-up
591
+ * @throws If API returned an error
592
+ */
593
+ async getTopUpConfig() {
594
+ return await this.coinbaseCDP.getOnRampConfig();
595
+ }
596
+ /**
597
+ * Return all supported countries and payment methods for off-ramp by Coinbase CDP
598
+ * @public
599
+ * @category Funding
600
+ *
601
+ *
602
+ * @returns @see {@link RampConfigResponse} with supported countries and payment methods for cash out
603
+ * @throws If API returned an error
604
+ */
605
+ async getCashOutConfig() {
606
+ return await this.coinbaseCDP.getOffRampConfig();
607
+ }
608
+ };
609
+
578
610
  // src/tools/ChainManager.ts
579
611
  import { createPublicClient, http } from "viem";
580
612
  import {
@@ -603,127 +635,6 @@ var chainById = Object.values(viemChains).reduce(
603
635
  {}
604
636
  );
605
637
 
606
- // src/types/logger.ts
607
- var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
608
- LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
609
- LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
610
- LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
611
- LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
612
- return LogLevel2;
613
- })(LogLevel || {});
614
-
615
- // src/tools/Logger.ts
616
- var Logger = class _Logger {
617
- /**
618
- * Create a new logger instance
619
- * @param logLevel Initial log level, defaults to DEBUG
620
- */
621
- constructor(logLevel = 0 /* DEBUG */) {
622
- this.logs = [];
623
- this.maxLogs = 1e3;
624
- this.logLevel = logLevel;
625
- }
626
- /**
627
- * Get singleton instance of the logger
628
- * @param logLevel Optional log level to initialize if instance not yet created
629
- * @returns Logger instance
630
- */
631
- static getInstance(logLevel) {
632
- if (!_Logger.instance) {
633
- _Logger.instance = new _Logger(logLevel);
634
- }
635
- return _Logger.instance;
636
- }
637
- /** Set the log level */
638
- setLogLevel(level) {
639
- this.logLevel = level;
640
- }
641
- /** Get the current log level */
642
- getLogLevel() {
643
- return this.logLevel;
644
- }
645
- /** Internal check if a message should be logged */
646
- shouldLog(level) {
647
- return level >= this.logLevel;
648
- }
649
- /** Format log message into a readable string */
650
- formatMessage(level, message, data, context) {
651
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
652
- const levelName = LogLevel[level];
653
- const contextStr = context ? `[${context}]` : "";
654
- return `${timestamp} ${levelName}${contextStr}: ${message}`;
655
- }
656
- /** Add a log entry and output to console */
657
- addLog(level, message, data, context) {
658
- if (!this.shouldLog(level)) {
659
- return;
660
- }
661
- const logEntry = {
662
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
663
- level,
664
- message,
665
- data,
666
- context
667
- };
668
- this.logs.push(logEntry);
669
- if (this.logs.length > this.maxLogs) {
670
- this.logs = this.logs.slice(-this.maxLogs);
671
- }
672
- const formattedMessage = this.formatMessage(level, message, data, context);
673
- switch (level) {
674
- case 0 /* DEBUG */:
675
- console.debug(`\u{1F50D} ${formattedMessage}`, data || "");
676
- break;
677
- case 1 /* INFO */:
678
- console.info(`\u2139\uFE0F ${formattedMessage}`, data || "");
679
- break;
680
- case 2 /* WARN */:
681
- console.warn(`\u26A0\uFE0F ${formattedMessage}`, data || "");
682
- break;
683
- case 3 /* ERROR */:
684
- console.error(`\u274C ${formattedMessage}`, data || "");
685
- break;
686
- }
687
- }
688
- /** Log a debug message */
689
- debug(message, data, context) {
690
- this.addLog(0 /* DEBUG */, message, data, context);
691
- }
692
- /** Log an info message */
693
- info(message, data, context) {
694
- this.addLog(1 /* INFO */, message, data, context);
695
- }
696
- /** Log a warning message */
697
- warn(message, data, context) {
698
- this.addLog(2 /* WARN */, message, data, context);
699
- }
700
- /** Log an error message */
701
- error(message, data, context) {
702
- this.addLog(3 /* ERROR */, message, data, context);
703
- }
704
- /** Get all logs */
705
- getLogs() {
706
- return [...this.logs];
707
- }
708
- /** Get logs by level */
709
- getLogsByLevel(level) {
710
- return this.logs.filter((log) => log.level === level);
711
- }
712
- /** Clear all logs */
713
- clearLogs() {
714
- this.logs = [];
715
- }
716
- /** Export logs as a JSON string */
717
- exportLogs() {
718
- return JSON.stringify(this.logs, null, 2);
719
- }
720
- /** Set maximum number of logs to retain in memory */
721
- setMaxLogs(max) {
722
- this.maxLogs = max;
723
- }
724
- };
725
- var logger = Logger.getInstance();
726
-
727
638
  // src/tools/ChainManager.ts
728
639
  var ChainManager = class {
729
640
  /**
@@ -779,7 +690,6 @@ var ChainManager = class {
779
690
  if (!bundlerUrl) {
780
691
  throw new Error(`No bundler URL configured for chain ID: ${chainId}`);
781
692
  }
782
- logger.info("Public client setup:", { bundlerUrl, chainId }, "ChainManager");
783
693
  const client = createPublicClient({
784
694
  chain: this.getChain(chainId),
785
695
  transport: http(rpcUrl)
@@ -882,32 +792,6 @@ var WalletNamespace = class {
882
792
  constructor(provider) {
883
793
  this.provider = provider;
884
794
  }
885
- /**
886
- * Direct access to the underlying embedded wallet provider
887
- *
888
- * @public
889
- * @category Providers
890
- * @remarks
891
- * Useful when you need advanced functionality beyond the unified namespace. By default, you should use the unified namespace
892
- *
893
- * @returns The configured embedded wallet provider instance
894
- */
895
- get embeddedWalletProvider() {
896
- return this.provider.embeddedWalletProvider;
897
- }
898
- /**
899
- * Direct access to the underlying smart wallet provider
900
- *
901
- * @public
902
- * @category Providers
903
- * @remarks
904
- * Useful when you need advanced functionality beyond the unified namespace. By default, you should use the unified namespace
905
- *
906
- * @returns The configured smart wallet provider instance
907
- */
908
- get smartWalletProvider() {
909
- return this.provider.smartWalletProvider;
910
- }
911
795
  /**
912
796
  * Creates an embedded wallet
913
797
  *
@@ -940,7 +824,7 @@ var WalletNamespace = class {
940
824
  return this.provider.createSmartWallet(params);
941
825
  }
942
826
  /**
943
- * Creates a smart wallet with an embedded wallet as signer
827
+ * A unified a web3 account: creates a smart wallet with an embedded wallet as signer
944
828
  *
945
829
  * @public
946
830
  * @category Creation
@@ -954,11 +838,11 @@ var WalletNamespace = class {
954
838
  * @param params.nonce Optional nonce/salt for deterministic address generation (defaults to 0)
955
839
  * @returns Promise that resolves to the created {@link SmartWallet}
956
840
  */
957
- async createWalletWithEmbeddedSigner(params) {
958
- return this.provider.createWalletWithEmbeddedSigner(params);
841
+ async createAccount(params) {
842
+ return this.provider.createAccount(params);
959
843
  }
960
844
  /**
961
- * Gets a smart wallet using an embedded wallet as the signer
845
+ * Gets a unified web3 account: a smart wallet using an embedded wallet as the signer
962
846
  *
963
847
  * @public
964
848
  * @category Retrieval
@@ -976,8 +860,8 @@ var WalletNamespace = class {
976
860
  * @returns Promise that resolves to the {@link SmartWallet}
977
861
  * @throws Error if the embedded wallet cannot be found
978
862
  */
979
- async getSmartWalletWithEmbeddedSigner(params) {
980
- return this.provider.getSmartWalletWithEmbeddedSigner(params);
863
+ async getAccount(params) {
864
+ return this.provider.getAccount(params);
981
865
  }
982
866
  /**
983
867
  * Gets an existing embedded wallet by ID
@@ -1038,7 +922,7 @@ var DefaultSmartWalletProvider = class extends SmartWalletProvider {
1038
922
  constructor(chainManager, protocol, coinbaseCDP) {
1039
923
  super();
1040
924
  this.chainManager = chainManager;
1041
- this.protocolProvider = protocol.instance;
925
+ this.protocolProvider = protocol;
1042
926
  this.coinbaseCDP = coinbaseCDP;
1043
927
  }
1044
928
  /**
@@ -1133,18 +1017,6 @@ var DefaultSmartWalletProvider = class extends SmartWalletProvider {
1133
1017
  ownerIndex
1134
1018
  );
1135
1019
  }
1136
- /**
1137
- * Funds a wallet via a faucet if supported by the selected chain
1138
- *
1139
- * @internal
1140
- * @category Funding
1141
- * @remarks
1142
- * Placeholder for testnet faucet integration
1143
- *
1144
- * @returns Future transaction hash or provider response
1145
- */
1146
- fundViaFaucet() {
1147
- }
1148
1020
  };
1149
1021
 
1150
1022
  // src/wallet/WalletProvider.ts
@@ -1208,9 +1080,12 @@ var WalletProvider = class {
1208
1080
  * @param params.nonce Optional salt/nonce for deterministic address calculation (defaults to 0)
1209
1081
  * @returns Promise that resolves to the created {@link SmartWallet}
1210
1082
  */
1211
- async createWalletWithEmbeddedSigner(params) {
1083
+ async createAccount(params) {
1212
1084
  const { owners: ownersParam, embeddedWalletIndex, nonce } = params || {};
1213
1085
  const embeddedWallet = await this.embeddedWalletProvider.createWallet();
1086
+ if (!embeddedWallet.walletId) {
1087
+ throw new Error("Failed to create embedded wallet. No wallet ID returned");
1088
+ }
1214
1089
  const account = await embeddedWallet.account();
1215
1090
  let owners;
1216
1091
  if (ownersParam) {
@@ -1220,14 +1095,18 @@ var WalletProvider = class {
1220
1095
  } else {
1221
1096
  owners = [embeddedWallet.address];
1222
1097
  }
1223
- return this.smartWalletProvider.createWallet({
1098
+ const smartWallet = await this.smartWalletProvider.createWallet({
1224
1099
  owners,
1225
1100
  signer: account,
1226
1101
  nonce
1227
1102
  });
1103
+ return {
1104
+ embeddedWalletId: embeddedWallet.walletId,
1105
+ smartWallet
1106
+ };
1228
1107
  }
1229
1108
  /**
1230
- * Gets a smart wallet using an embedded wallet as the signer
1109
+ * Gets a unified web3 account: a smart wallet using an embedded wallet as the signer
1231
1110
  *
1232
1111
  * @internal
1233
1112
  * @remarks
@@ -1244,7 +1123,7 @@ var WalletProvider = class {
1244
1123
  * @returns Promise that resolves to the {@link SmartWallet}
1245
1124
  * @throws Error if the embedded wallet cannot be found
1246
1125
  */
1247
- async getSmartWalletWithEmbeddedSigner(params) {
1126
+ async getAccount(params) {
1248
1127
  const { walletId, deploymentOwners, walletAddress } = params;
1249
1128
  const embeddedWallet = await this.embeddedWalletProvider.getWallet({
1250
1129
  walletId
@@ -1306,8 +1185,7 @@ var WalletProvider = class {
1306
1185
  throw new Error(
1307
1186
  "Either walletAddress or deploymentOwners array must be provided to locate the smart wallet"
1308
1187
  );
1309
- } catch (error) {
1310
- logger.error("Error getting smart wallet", error, "WalletProvider");
1188
+ } catch {
1311
1189
  throw new Error(
1312
1190
  "Either walletAddress or deploymentOwners array must be provided to locate the smart wallet"
1313
1191
  );
@@ -1353,6 +1231,127 @@ var EmbeddedWallet = class {
1353
1231
  }
1354
1232
  };
1355
1233
 
1234
+ // src/types/logger.ts
1235
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
1236
+ LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
1237
+ LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
1238
+ LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
1239
+ LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
1240
+ return LogLevel2;
1241
+ })(LogLevel || {});
1242
+
1243
+ // src/tools/Logger.ts
1244
+ var Logger = class _Logger {
1245
+ /**
1246
+ * Create a new logger instance
1247
+ * @param logLevel Initial log level, defaults to DEBUG
1248
+ */
1249
+ constructor(logLevel = 0 /* DEBUG */) {
1250
+ this.logs = [];
1251
+ this.maxLogs = 1e3;
1252
+ this.logLevel = logLevel;
1253
+ }
1254
+ /**
1255
+ * Get singleton instance of the logger
1256
+ * @param logLevel Optional log level to initialize if instance not yet created
1257
+ * @returns Logger instance
1258
+ */
1259
+ static getInstance(logLevel) {
1260
+ if (!_Logger.instance) {
1261
+ _Logger.instance = new _Logger(logLevel);
1262
+ }
1263
+ return _Logger.instance;
1264
+ }
1265
+ /** Set the log level */
1266
+ setLogLevel(level) {
1267
+ this.logLevel = level;
1268
+ }
1269
+ /** Get the current log level */
1270
+ getLogLevel() {
1271
+ return this.logLevel;
1272
+ }
1273
+ /** Internal check if a message should be logged */
1274
+ shouldLog(level) {
1275
+ return level >= this.logLevel;
1276
+ }
1277
+ /** Format log message into a readable string */
1278
+ formatMessage(level, message, data, context) {
1279
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1280
+ const levelName = LogLevel[level];
1281
+ const contextStr = context ? `[${context}]` : "";
1282
+ return `${timestamp} ${levelName}${contextStr}: ${message}`;
1283
+ }
1284
+ /** Add a log entry and output to console */
1285
+ addLog(level, message, data, context) {
1286
+ if (!this.shouldLog(level)) {
1287
+ return;
1288
+ }
1289
+ const logEntry = {
1290
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1291
+ level,
1292
+ message,
1293
+ data,
1294
+ context
1295
+ };
1296
+ this.logs.push(logEntry);
1297
+ if (this.logs.length > this.maxLogs) {
1298
+ this.logs = this.logs.slice(-this.maxLogs);
1299
+ }
1300
+ const formattedMessage = this.formatMessage(level, message, data, context);
1301
+ switch (level) {
1302
+ case 0 /* DEBUG */:
1303
+ console.debug(`\u{1F50D} ${formattedMessage}`, data || "");
1304
+ break;
1305
+ case 1 /* INFO */:
1306
+ console.info(`\u2139\uFE0F ${formattedMessage}`, data || "");
1307
+ break;
1308
+ case 2 /* WARN */:
1309
+ console.warn(`\u26A0\uFE0F ${formattedMessage}`, data || "");
1310
+ break;
1311
+ case 3 /* ERROR */:
1312
+ console.error(`\u274C ${formattedMessage}`, data || "");
1313
+ break;
1314
+ }
1315
+ }
1316
+ /** Log a debug message */
1317
+ debug(message, data, context) {
1318
+ this.addLog(0 /* DEBUG */, message, data, context);
1319
+ }
1320
+ /** Log an info message */
1321
+ info(message, data, context) {
1322
+ this.addLog(1 /* INFO */, message, data, context);
1323
+ }
1324
+ /** Log a warning message */
1325
+ warn(message, data, context) {
1326
+ this.addLog(2 /* WARN */, message, data, context);
1327
+ }
1328
+ /** Log an error message */
1329
+ error(message, data, context) {
1330
+ this.addLog(3 /* ERROR */, message, data, context);
1331
+ }
1332
+ /** Get all logs */
1333
+ getLogs() {
1334
+ return [...this.logs];
1335
+ }
1336
+ /** Get logs by level */
1337
+ getLogsByLevel(level) {
1338
+ return this.logs.filter((log) => log.level === level);
1339
+ }
1340
+ /** Clear all logs */
1341
+ clearLogs() {
1342
+ this.logs = [];
1343
+ }
1344
+ /** Export logs as a JSON string */
1345
+ exportLogs() {
1346
+ return JSON.stringify(this.logs, null, 2);
1347
+ }
1348
+ /** Set maximum number of logs to retain in memory */
1349
+ setMaxLogs(max) {
1350
+ this.maxLogs = max;
1351
+ }
1352
+ };
1353
+ var logger = Logger.getInstance();
1354
+
1356
1355
  // src/wallet/PrivyWallet.ts
1357
1356
  var PrivyWallet = class extends EmbeddedWallet {
1358
1357
  /**
@@ -1676,12 +1675,7 @@ var BaseProtocol = class {
1676
1675
  };
1677
1676
 
1678
1677
  // src/protocols/implementations/SparkProtocol.ts
1679
- import {
1680
- encodeFunctionData as encodeFunctionData2,
1681
- erc20Abi as erc20Abi4,
1682
- formatUnits as formatUnits2,
1683
- parseUnits as parseUnits2
1684
- } from "viem";
1678
+ import { encodeFunctionData as encodeFunctionData2, erc20Abi as erc20Abi4, formatUnits as formatUnits2, parseUnits as parseUnits2 } from "viem";
1685
1679
 
1686
1680
  // src/abis/protocols/spark.ts
1687
1681
  var SPARK_VAULT_ABI = [
@@ -1743,14 +1737,14 @@ var SPARK_SSR_ORACLE_ADDRESS = "0x65d946e533748A998B1f0E430803e39A6388f7a1";
1743
1737
  var SPARK_VAULT = [
1744
1738
  {
1745
1739
  id: "sUSDC",
1740
+ protocolId: "spark",
1741
+ name: "sUSDC",
1742
+ type: "stable",
1746
1743
  chain: "base",
1747
1744
  vaultAddress: "0x3128a0f7f0ea68e7b7c9b00afa7e41045828e858",
1748
- depositTokenAddress: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1749
- depositTokenDecimals: 6,
1750
- depositTokenSymbol: "USDC",
1751
- earnTokenAddress: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1752
- earnTokenDecimals: 18,
1753
- earnTokenSymbol: "sUSDC",
1745
+ tokenAddress: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1746
+ tokenDecimals: 6,
1747
+ tokenSymbol: "USDC",
1754
1748
  metadata: {}
1755
1749
  }
1756
1750
  ];
@@ -1761,6 +1755,7 @@ var RAY = BigInt("1000000000000000000000000000");
1761
1755
  var SparkProtocol = class extends BaseProtocol {
1762
1756
  constructor() {
1763
1757
  super(...arguments);
1758
+ /** All Spark vaults */
1764
1759
  this.allVaults = [];
1765
1760
  }
1766
1761
  /**
@@ -1771,7 +1766,7 @@ var SparkProtocol = class extends BaseProtocol {
1771
1766
  this.chainManager = chainManager;
1772
1767
  this.selectedChainId = chainManager.getSupportedChain();
1773
1768
  this.publicClient = chainManager.getPublicClient(this.selectedChainId);
1774
- this.allVaults = this.getVaults();
1769
+ this.allVaults = SPARK_VAULT;
1775
1770
  }
1776
1771
  /**
1777
1772
  * Get the SSR (Sky Saving Rate) of the Spark protocol
@@ -1801,88 +1796,54 @@ var SparkProtocol = class extends BaseProtocol {
1801
1796
  async getAPY() {
1802
1797
  const ssr = await this.getSSR();
1803
1798
  const apy = Math.exp(Math.log(ssr) * SECONDS_PER_YEAR) - 1;
1804
- return Number((apy * 100).toFixed(2));
1799
+ return apy;
1805
1800
  }
1806
1801
  /**
1807
- *
1808
- * Get all vault info from a Spark protocol
1809
- * @returns The list of vaults
1810
- */
1811
- getVaults() {
1812
- return SPARK_VAULT;
1813
- }
1814
- /**
1815
- * Get the best available Spark vault
1816
- * @returns The top-ranked Spark vault
1802
+ * Get the best available Spark vaults
1803
+ * @remarks Currently, the vault is only one and relates to sUSDC. Currently return only one stable vault
1804
+ * @returns Best Spark vaults in 2 groups: stable and non-stable
1817
1805
  * @throws Error if no vaults found
1818
1806
  */
1819
- async getBestVault() {
1807
+ async getBestVaults() {
1820
1808
  if (this.allVaults.length === 0) {
1821
1809
  throw new Error("No vaults found");
1822
1810
  }
1823
1811
  const selectedVault = this.allVaults[0];
1824
1812
  selectedVault.metadata.apy = await this.getAPY();
1825
- return selectedVault;
1826
- }
1827
- /**
1828
- * Fetch a vault where the user previously deposited funds
1829
- * @param smartWallet Smart wallet to inspect
1830
- * @returns The vault with user deposits, or null if none found
1831
- */
1832
- async fetchDepositedVaults(smartWallet) {
1833
- let depositedVault = void 0;
1834
- const userAddress = await smartWallet.getAddress();
1835
- for (const vault of this.allVaults) {
1836
- const balance = await this.getBalance(vault, userAddress);
1837
- if (parseInt(balance.depositedAmount) > 0) {
1838
- depositedVault = vault;
1839
- }
1840
- }
1841
- if (depositedVault) {
1842
- depositedVault.metadata.apy = await this.getAPY();
1843
- }
1844
- logger.info("Deposited vaults:", { depositedVault }, "SparkProtocol");
1845
- return depositedVault || null;
1813
+ return {
1814
+ stable: [selectedVault],
1815
+ nonStable: []
1816
+ };
1846
1817
  }
1847
1818
  /**
1848
1819
  * Deposit funds into a Spark vault
1820
+ * @param vaultInfo Vault information
1849
1821
  * @param amount Amount to deposit (human-readable)
1850
1822
  * @param smartWallet Smart wallet instance to use
1851
1823
  * @returns Transaction result with hash
1852
1824
  */
1853
- async deposit(amount, smartWallet) {
1854
- const depositedVault = await this.fetchDepositedVaults(smartWallet);
1855
- let vaultInfoToDeposit;
1856
- logger.info("Previously deposited vault:", { depositedVault }, "SparkProtocol");
1857
- if (depositedVault) {
1858
- vaultInfoToDeposit = depositedVault;
1859
- } else {
1860
- vaultInfoToDeposit = await this.getBestVault();
1861
- logger.info("Best vault that found:", { bestVault: vaultInfoToDeposit }, "SparkProtocol");
1862
- }
1825
+ async deposit(vaultInfo, amount, smartWallet) {
1863
1826
  const owner = await smartWallet.getAddress();
1864
- const assets = parseUnits2(amount, vaultInfoToDeposit.depositTokenDecimals);
1865
- logger.info("Raw deposit amount:", { amount, assets }, "SparkProtocol");
1827
+ const assets = parseUnits2(amount, vaultInfo.tokenDecimals);
1866
1828
  const allowance = await this.checkAllowance(
1867
- vaultInfoToDeposit.depositTokenAddress,
1868
- vaultInfoToDeposit.vaultAddress,
1829
+ vaultInfo.tokenAddress,
1830
+ vaultInfo.vaultAddress,
1869
1831
  owner,
1870
1832
  this.selectedChainId
1871
1833
  );
1872
- logger.info("Current vault contract allowance:", { allowance }, "SparkProtocol");
1873
1834
  const ops = [];
1874
1835
  if (allowance < assets) {
1875
1836
  ops.push({
1876
- to: vaultInfoToDeposit.depositTokenAddress,
1837
+ to: vaultInfo.tokenAddress,
1877
1838
  data: encodeFunctionData2({
1878
1839
  abi: erc20Abi4,
1879
1840
  functionName: "approve",
1880
- args: [vaultInfoToDeposit.vaultAddress, assets]
1841
+ args: [vaultInfo.vaultAddress, assets]
1881
1842
  })
1882
1843
  });
1883
1844
  }
1884
1845
  ops.push({
1885
- to: vaultInfoToDeposit.vaultAddress,
1846
+ to: vaultInfo.vaultAddress,
1886
1847
  data: encodeFunctionData2({
1887
1848
  abi: SPARK_VAULT_ABI,
1888
1849
  functionName: "deposit",
@@ -1894,23 +1855,19 @@ var SparkProtocol = class extends BaseProtocol {
1894
1855
  }
1895
1856
  /**
1896
1857
  * Withdraw funds from a Spark vault
1897
- * @param amountInUnderlying Amount in base token units (or undefined to withdraw all)
1858
+ * @param vaultInfo Vault information
1859
+ * @param amount Amount in base token units (or undefined to withdraw all)
1898
1860
  * @param smartWallet Smart wallet instance to withdraw from
1899
1861
  * @returns Transaction result with hash
1900
1862
  * @throws Error if no deposited vault found
1901
1863
  */
1902
- async withdraw(amountInUnderlying, smartWallet) {
1903
- const depositedVault = await this.fetchDepositedVaults(smartWallet);
1904
- if (!depositedVault) {
1905
- throw new Error("No vault found to withdraw from");
1906
- }
1864
+ async withdraw(vaultInfo, amount, smartWallet) {
1907
1865
  const owner = await smartWallet.getAddress();
1908
1866
  let withdrawData;
1909
- if (amountInUnderlying) {
1910
- const assets = parseUnits2(amountInUnderlying, depositedVault.depositTokenDecimals);
1911
- logger.info("Withdraw amount:", { amountInUnderlying, assets }, "SparkProtocol");
1867
+ if (amount) {
1868
+ const assets = parseUnits2(amount, vaultInfo.tokenDecimals);
1912
1869
  withdrawData = {
1913
- to: depositedVault.vaultAddress,
1870
+ to: vaultInfo.vaultAddress,
1914
1871
  data: encodeFunctionData2({
1915
1872
  abi: SPARK_VAULT_ABI,
1916
1873
  functionName: "withdraw",
@@ -1918,10 +1875,9 @@ var SparkProtocol = class extends BaseProtocol {
1918
1875
  })
1919
1876
  };
1920
1877
  } else {
1921
- const maxShares = await this.getMaxRedeemableShares(depositedVault, owner);
1922
- logger.info("Withdrawing all funds:", { maxShares }, "SparkProtocol");
1878
+ const maxShares = await this.getMaxRedeemableShares(vaultInfo, owner);
1923
1879
  withdrawData = {
1924
- to: depositedVault.vaultAddress,
1880
+ to: vaultInfo.vaultAddress,
1925
1881
  data: encodeFunctionData2({
1926
1882
  abi: SPARK_VAULT_ABI,
1927
1883
  functionName: "redeem",
@@ -1930,7 +1886,6 @@ var SparkProtocol = class extends BaseProtocol {
1930
1886
  };
1931
1887
  }
1932
1888
  const hash = await smartWallet.send(withdrawData, this.selectedChainId);
1933
- logger.info("Withdraw transaction sent:", { hash }, "SparkProtocol");
1934
1889
  return { success: true, hash };
1935
1890
  }
1936
1891
  /**
@@ -1953,14 +1908,15 @@ var SparkProtocol = class extends BaseProtocol {
1953
1908
  }
1954
1909
  /**
1955
1910
  * Get amount that a wallet has deposited in a vault
1956
- * @param vaultInfo Vault information
1957
1911
  * @param walletAddress Wallet address to check
1958
- * @returns Object containing shares and deposited amount
1912
+ * @returns Array of vault balances with vaults info
1959
1913
  */
1960
- async getBalance(vaultInfo, walletAddress) {
1914
+ async getBalances(walletAddress) {
1961
1915
  if (!this.publicClient) {
1962
1916
  throw new Error("Public client not initialized");
1963
1917
  }
1918
+ const vaultInfo = SPARK_VAULT[0];
1919
+ vaultInfo.metadata.apy = await this.getAPY();
1964
1920
  const shares = await this.publicClient.readContract({
1965
1921
  address: vaultInfo.vaultAddress,
1966
1922
  abi: SPARK_VAULT_ABI,
@@ -1968,7 +1924,7 @@ var SparkProtocol = class extends BaseProtocol {
1968
1924
  args: [walletAddress]
1969
1925
  });
1970
1926
  if (shares === 0n) {
1971
- return { shares: "0", depositedAmount: "0", vaultInfo };
1927
+ return [{ balance: null, vaultInfo }];
1972
1928
  }
1973
1929
  const assets = await this.publicClient.readContract({
1974
1930
  address: vaultInfo.vaultAddress,
@@ -1976,11 +1932,12 @@ var SparkProtocol = class extends BaseProtocol {
1976
1932
  functionName: "convertToAssets",
1977
1933
  args: [shares]
1978
1934
  });
1979
- return {
1980
- shares: formatUnits2(shares, vaultInfo.earnTokenDecimals),
1981
- depositedAmount: formatUnits2(assets, vaultInfo.depositTokenDecimals),
1982
- vaultInfo
1983
- };
1935
+ return [
1936
+ {
1937
+ balance: formatUnits2(assets, vaultInfo.tokenDecimals),
1938
+ vaultInfo
1939
+ }
1940
+ ];
1984
1941
  }
1985
1942
  };
1986
1943
 
@@ -1992,59 +1949,233 @@ var availableProtocols = [
1992
1949
  name: "Spark",
1993
1950
  website: "https://spark.fi/",
1994
1951
  logo: "/logos/spark.png",
1995
- supportedChains: [1, 8453, 42161],
1952
+ supportedChains: [8453],
1996
1953
  riskLevel: "low",
1997
- isPremium: false
1954
+ isActive: true
1998
1955
  },
1999
1956
  instance: new SparkProtocol()
2000
1957
  }
2001
1958
  ];
2002
1959
 
2003
- // src/tools/ApiKeysValidator.ts
2004
- var ApiKeysValidator = class {
2005
- // TODO: Implement the validation logic
1960
+ // src/protocols/implementations/ProxyProtocol.ts
1961
+ import { encodeFunctionData as encodeFunctionData3, erc20Abi as erc20Abi5, parseUnits as parseUnits3 } from "viem";
1962
+ var ProxyProtocol = class extends BaseProtocol {
2006
1963
  /**
2007
- * Validates whether the provided API key is valid
2008
- *
2009
- * @internal
2010
- * @param apiKey API key from {@link ProtocolsRouterConfig}
2011
- * @returns True if the API key is considered valid
1964
+ * Initialize the Spark protocol with the provided chain manager
1965
+ * @param chainManager Chain manager instance used for network operations
2012
1966
  */
2013
- validate(apiKey) {
2014
- logger.info("Validating api key...", apiKey, "ApiKeysValidator");
2015
- return true;
2016
- }
2017
- };
2018
-
2019
- // src/router/base/ProtocolRouterBase.ts
2020
- var ProtocolRouterBase = class {
2021
- /**
2022
- * Initialize a base protocol router
2023
- * @param riskLevel Risk level required by the integrator
2024
- * @param chainManager Chain manager instance for network operations
2025
- * @param minApy Optional minimum APY filter
2026
- * @param apiKey Optional API key for premium protocol access
2027
- */
2028
- constructor(riskLevel, chainManager, minApy, apiKey) {
2029
- // TODO: Add an API key validation
2030
- /** API key validator instance */
2031
- this.apiKeyValidator = new ApiKeysValidator();
2032
- this.riskLevel = riskLevel;
2033
- this.minApy = minApy;
2034
- this.apiKey = apiKey;
1967
+ async init(chainManager, protocolsSecurityConfig, apiClient) {
2035
1968
  this.chainManager = chainManager;
1969
+ this.selectedChainId = chainManager.getSupportedChain();
1970
+ this.publicClient = chainManager.getPublicClient(this.selectedChainId);
1971
+ this.apiClient = apiClient;
1972
+ this.protocolsSecurityConfig = protocolsSecurityConfig;
1973
+ }
1974
+ /**
1975
+ * Log a vault-related operation after deposit or withdraw funds
1976
+ * @param userAddress Address of the user who performed the operation
1977
+ * @param hash Hash of the operation
1978
+ * @param vaultInfo Information about the vault where the operation was performed
1979
+ * @param chainId Chain ID where the operation was performed
1980
+ * @param amount Amount of the operation
1981
+ * @param operationType Type of the operation
1982
+ * @param operationStatus Status of the operation
1983
+ */
1984
+ async logOperation(userAddress, hash, vaultInfo, chainId, amount, operationType, operationStatus) {
1985
+ const apiResponse = await this.apiClient.sendRequest("log", void 0, void 0, {
1986
+ userAddress,
1987
+ protocolId: vaultInfo.protocolId,
1988
+ vaultAddress: vaultInfo.vaultAddress,
1989
+ transactionHash: hash,
1990
+ chainId: chainId.toString(),
1991
+ amount,
1992
+ status: operationStatus,
1993
+ operationType
1994
+ });
1995
+ if (!apiResponse.success) {
1996
+ throw new Error(
1997
+ apiResponse.error || `Failed to log operation: ${operationType} for vault: ${vaultInfo}`
1998
+ );
1999
+ }
2000
+ }
2001
+ /**
2002
+ * Get the best vaults to deposit funds
2003
+ * @param stableVaultsLimit Limit of stable vaults to get. Optional, default is 1
2004
+ * @param nonStableVaultsLimit Limit of non-stable vaults to get. Optional, default is 1
2005
+ * @returns Best vaults to deposit funds in 2 groups: stable and non-stable
2006
+ */
2007
+ async getBestVaults(stableVaultsLimit = 1, nonStableVaultsLimit = 1) {
2008
+ const pathParams = {
2009
+ risk_level: this.protocolsSecurityConfig.riskLevel,
2010
+ chain_id: this.selectedChainId.toString(),
2011
+ stable_vaults_limit: stableVaultsLimit.toString(),
2012
+ non_stable_vaults_limit: nonStableVaultsLimit.toString()
2013
+ };
2014
+ const apiResponse = await this.apiClient.sendRequest("vaults", pathParams);
2015
+ if (!apiResponse.success) {
2016
+ throw new Error(apiResponse.error || "Failed to get best vaults");
2017
+ }
2018
+ const vaults = apiResponse.data;
2019
+ return {
2020
+ stable: vaults.stableVaults.map((vault) => {
2021
+ return {
2022
+ ...vault,
2023
+ metadata: {
2024
+ apy: vault.metadata?.apy,
2025
+ poolTvlUsd: vault.metadata?.poolTvlUsd
2026
+ }
2027
+ };
2028
+ }),
2029
+ nonStable: vaults.nonStableVaults.map((vault) => {
2030
+ return {
2031
+ ...vault,
2032
+ metadata: {
2033
+ apy: vault.metadata?.apy,
2034
+ poolTvlUsd: vault.metadata?.poolTvlUsd
2035
+ }
2036
+ };
2037
+ })
2038
+ };
2039
+ }
2040
+ /**
2041
+ * Deposit funds to a provided vault
2042
+ * @param vaultInfo Information about the vault to deposit funds to
2043
+ * @param amount Amount of funds to deposit
2044
+ * @param smartWallet Smart wallet to use for the deposit
2045
+ * @returns Result of the deposit transaction
2046
+ */
2047
+ async deposit(vaultInfo, amount, smartWallet) {
2048
+ const currentAddress = await smartWallet.getAddress();
2049
+ const operationsCallData = [];
2050
+ const depositTokenDecimals = vaultInfo.tokenDecimals;
2051
+ const depositTokenAddress = vaultInfo.tokenAddress;
2052
+ const vaultAddress = vaultInfo.vaultAddress;
2053
+ const rawDepositAmount = parseUnits3(amount, depositTokenDecimals);
2054
+ const allowance = await this.checkAllowance(
2055
+ depositTokenAddress,
2056
+ vaultAddress,
2057
+ currentAddress,
2058
+ this.selectedChainId
2059
+ );
2060
+ if (allowance < rawDepositAmount) {
2061
+ const approveData = {
2062
+ to: depositTokenAddress,
2063
+ data: encodeFunctionData3({
2064
+ abi: erc20Abi5,
2065
+ functionName: "approve",
2066
+ args: [vaultAddress, rawDepositAmount]
2067
+ })
2068
+ };
2069
+ operationsCallData.push(approveData);
2070
+ }
2071
+ if (!vaultInfo.protocolId) {
2072
+ throw new Error("Vault protocol ID is required");
2073
+ }
2074
+ const apiResponse = await this.apiClient.sendRequest(
2075
+ "deposit",
2076
+ void 0,
2077
+ vaultInfo.protocolId,
2078
+ {
2079
+ vaultInfo,
2080
+ amount: amount.toString(),
2081
+ chainId: this.selectedChainId.toString()
2082
+ }
2083
+ );
2084
+ if (!apiResponse.success) {
2085
+ throw new Error(apiResponse.error || "Failed to receive deposit operations call data");
2086
+ }
2087
+ const receivedOperationsCallData = apiResponse.data;
2088
+ operationsCallData.push(receivedOperationsCallData);
2089
+ const hash = await smartWallet.sendBatch(operationsCallData, this.selectedChainId);
2090
+ const operationStatus = hash ? "completed" : "failed";
2091
+ this.logOperation(
2092
+ currentAddress,
2093
+ hash,
2094
+ vaultInfo,
2095
+ this.selectedChainId,
2096
+ amount,
2097
+ "deposit",
2098
+ operationStatus
2099
+ );
2100
+ return { hash, success: true };
2101
+ }
2102
+ /**
2103
+ * Withdraw funds from a provided vault
2104
+ * @param vaultInfo Information about the vault to withdraw funds from
2105
+ * @param amount Amount of funds to withdraw
2106
+ * @param smartWallet Smart wallet to use for the withdrawal
2107
+ * @returns Result of the withdrawal transaction
2108
+ */
2109
+ async withdraw(vaultInfo, amount, smartWallet) {
2110
+ const currentAddress = await smartWallet.getAddress();
2111
+ const earningBalances = await smartWallet.getEarnBalances();
2112
+ if (!earningBalances) {
2113
+ throw new Error("No earning balances found");
2114
+ }
2115
+ const earningBalance = earningBalances.find((balance) => balance.vaultInfo.id === vaultInfo.id);
2116
+ if (!earningBalance) {
2117
+ throw new Error("No earning balance found");
2118
+ }
2119
+ const balanceInfo = earningBalance.balance;
2120
+ const amountToWithdraw = amount ? amount : balanceInfo.currentBalance;
2121
+ const apiResponse = await this.apiClient.sendRequest(
2122
+ "withdraw",
2123
+ void 0,
2124
+ vaultInfo.protocolId,
2125
+ {
2126
+ vaultInfo,
2127
+ amount: amountToWithdraw,
2128
+ chainId: this.selectedChainId.toString()
2129
+ }
2130
+ );
2131
+ if (!apiResponse.success) {
2132
+ throw new Error(apiResponse.error || "Failed to receive withdraw operations call data");
2133
+ }
2134
+ const withdrawOperationCallData = apiResponse.data;
2135
+ const hash = await smartWallet.send(withdrawOperationCallData, this.selectedChainId);
2136
+ const operationStatus = hash ? "completed" : "failed";
2137
+ this.logOperation(
2138
+ currentAddress,
2139
+ hash,
2140
+ vaultInfo,
2141
+ this.selectedChainId,
2142
+ amountToWithdraw,
2143
+ "withdrawal",
2144
+ operationStatus
2145
+ );
2146
+ return { hash, success: true };
2147
+ }
2148
+ /**
2149
+ * Get the balances of a user by a provided address
2150
+ * @param walletAddress Address of the user to get the balances of
2151
+ * @param protocolId Protocol ID to get the balances for. Optional, default is undefined
2152
+ * @returns Balances of the user in the protocol vaults
2153
+ */
2154
+ async getBalances(walletAddress, protocolId) {
2155
+ const pathParams = {
2156
+ chain_id: this.selectedChainId.toString(),
2157
+ protocol_id: protocolId || "",
2158
+ userAddress: walletAddress
2159
+ };
2160
+ const apiResponse = await this.apiClient.sendRequest("balances", pathParams);
2161
+ if (!apiResponse.success) {
2162
+ throw new Error(apiResponse.error || "Failed to get balances");
2163
+ }
2164
+ const balances = apiResponse.data;
2165
+ return balances;
2036
2166
  }
2037
2167
  };
2038
2168
 
2039
2169
  // src/router/ProtocolRouter.ts
2040
- var ProtocolRouter = class extends ProtocolRouterBase {
2170
+ var ProtocolRouter = class {
2041
2171
  /**
2042
2172
  * Initialize the protocol router
2043
2173
  * @param config Router configuration including risk level, min APY, and optional API key
2044
2174
  * @param chainManager Chain manager instance for network validation
2045
2175
  */
2046
- constructor(config, chainManager) {
2047
- super(config.riskLevel, chainManager, config.minApy, config.apiKey);
2176
+ constructor(chainManager, isApiKeyValid) {
2177
+ this.chainManager = chainManager;
2178
+ this.isApiKeyValid = isApiKeyValid;
2048
2179
  }
2049
2180
  /**
2050
2181
  * Get all protocols available for the current configuration
@@ -2052,13 +2183,9 @@ var ProtocolRouter = class extends ProtocolRouterBase {
2052
2183
  * Includes all non-premium protocols and premium protocols if the API key is valid
2053
2184
  * @returns Array of available protocol definitions
2054
2185
  */
2055
- getProtocols() {
2056
- const isKeyValid = this.apiKeyValidator.validate(this.apiKey);
2186
+ getActivePublicProtocols() {
2057
2187
  const allAvailableProtocols = availableProtocols.filter((protocol) => {
2058
- if (!protocol.info.isPremium) {
2059
- return true;
2060
- }
2061
- return protocol.info.isPremium && isKeyValid;
2188
+ return protocol.info.isActive;
2062
2189
  });
2063
2190
  return allAvailableProtocols;
2064
2191
  }
@@ -2083,18 +2210,20 @@ var ProtocolRouter = class extends ProtocolRouterBase {
2083
2210
  * @throws Error if no protocols are available for the current risk level
2084
2211
  * @returns Protocol instance considered the best match
2085
2212
  */
2086
- recommend() {
2087
- const protocols = this.getProtocols();
2213
+ select() {
2214
+ if (this.isApiKeyValid) {
2215
+ return new ProxyProtocol();
2216
+ }
2217
+ const protocols = this.getActivePublicProtocols();
2088
2218
  const eligibleProtocols = protocols.filter((protocol) => {
2089
- const riskMatches = protocol.info.riskLevel === this.riskLevel;
2090
2219
  const isSupportedChain = this.isProtocolSupportedChain(protocol.info.supportedChains);
2091
- return riskMatches && isSupportedChain;
2220
+ return isSupportedChain;
2092
2221
  });
2093
2222
  if (eligibleProtocols.length === 0) {
2094
- throw new Error(`No protocols available for risk level: ${this.riskLevel}`);
2223
+ throw new Error(`No protocols available`);
2095
2224
  }
2096
2225
  const bestProtocol = eligibleProtocols[0];
2097
- return bestProtocol;
2226
+ return bestProtocol.instance;
2098
2227
  }
2099
2228
  };
2100
2229
 
@@ -2314,8 +2443,161 @@ var CoinbaseCDP = class {
2314
2443
  }
2315
2444
  };
2316
2445
 
2446
+ // src/protocols/ProtocolsNamespace.ts
2447
+ var ProtocolsNamespace = class {
2448
+ constructor(protocol) {
2449
+ this.protocol = protocol;
2450
+ }
2451
+ /**
2452
+ * Find the best vaults for protocols that were selected based on integrator's settings
2453
+ *
2454
+ * @returns Best vaults for protocols that were selected based on integrator's settings
2455
+ */
2456
+ async getBestVaults(stableVaultsLimit = 1, nonStableVaultsLimit = 1) {
2457
+ return await this.protocol.getBestVaults(stableVaultsLimit, nonStableVaultsLimit);
2458
+ }
2459
+ };
2460
+
2461
+ // src/constants/general.ts
2462
+ var BACKEND_HOSTNAME = "http://localhost:3000";
2463
+
2464
+ // src/tools/ApiClient.ts
2465
+ import axios2 from "axios";
2466
+ var ApiClient = class {
2467
+ constructor(apiKey) {
2468
+ this.client = axios2.create({
2469
+ baseURL: BACKEND_HOSTNAME
2470
+ });
2471
+ /** URL settings for the endpoint: get the best vaults to deposit funds */
2472
+ this.bestVaultUrlSettings = {
2473
+ method: "GET",
2474
+ path: "api/v1/public/protocols/best"
2475
+ };
2476
+ /** URL settings for the endpoint: deposit funds to a provided vault */
2477
+ this.depositUrlSettings = {
2478
+ method: "POST",
2479
+ path: "api/v1/public/protocols/details/:protocolId/deposit"
2480
+ };
2481
+ /** URL settings for the endpoint: log a vault-related operation after deposit or withdraw funds */
2482
+ this.logOperationSettings = {
2483
+ method: "POST",
2484
+ path: "api/v1/public/log/operation"
2485
+ };
2486
+ /** URL settings for the endpoint: withdraw funds from a provided vault */
2487
+ this.withdrawUrlSettings = {
2488
+ method: "POST",
2489
+ path: "api/v1/public/protocols/details/:protocolId/withdraw"
2490
+ };
2491
+ /** URL settings for the endpoint: get the balances of a user by a provided address */
2492
+ this.balancesUrlSettings = {
2493
+ method: "GET",
2494
+ path: "api/v1/public/user/:userAddress/balances"
2495
+ };
2496
+ /** URL settings for the endpoint: validate the API key */
2497
+ this.apiKeyValidUrlSettings = {
2498
+ method: "GET",
2499
+ path: "api/v1/public/valid"
2500
+ };
2501
+ /** URL settings for the endpoint: get the config for services */
2502
+ this.configUrlSettings = {
2503
+ method: "GET",
2504
+ path: "api/v1/public/config"
2505
+ };
2506
+ /** URL settings mapping with operation types */
2507
+ this.operationTypeToUrlSettings = {
2508
+ deposit: this.depositUrlSettings,
2509
+ withdraw: this.withdrawUrlSettings,
2510
+ log: this.logOperationSettings,
2511
+ vaults: this.bestVaultUrlSettings,
2512
+ balances: this.balancesUrlSettings,
2513
+ apiKeyValidation: this.apiKeyValidUrlSettings,
2514
+ config: this.configUrlSettings
2515
+ };
2516
+ this.apiKey = apiKey;
2517
+ if (!this.validateApiKeyFormat()) {
2518
+ throw new Error("Invalid API key format");
2519
+ }
2520
+ }
2521
+ /**
2522
+ * Send a request to the backend API
2523
+ * @param path Path of the endpoint to send the request to
2524
+ * @param method Method of the request
2525
+ * @param body Body of the request
2526
+ * @returns Response from the backend API
2527
+ */
2528
+ async sendRequest(operationType, params, protocolId, body) {
2529
+ const { path, method } = this.operationTypeToUrlSettings[operationType];
2530
+ let requestPath = path;
2531
+ if (protocolId) {
2532
+ requestPath = requestPath.replace(":protocolId", protocolId);
2533
+ }
2534
+ if (params?.userAddress) {
2535
+ requestPath = requestPath.replace(":userAddress", params.userAddress);
2536
+ delete params.userAddress;
2537
+ }
2538
+ const urlParams = new URLSearchParams(params).toString();
2539
+ if (urlParams) {
2540
+ requestPath += `?${urlParams}`;
2541
+ }
2542
+ const response = await this.client.request({
2543
+ method,
2544
+ url: requestPath,
2545
+ data: body,
2546
+ headers: { Authorization: `Bearer ${this.apiKey}`, "Content-Type": "application/json" }
2547
+ });
2548
+ if (response.status !== 200) {
2549
+ throw new Error(`Failed to send request to ${path}`);
2550
+ }
2551
+ const apiResponse = response.data;
2552
+ return apiResponse;
2553
+ }
2554
+ /**
2555
+ * Validates whether the provided API key is valid
2556
+ *
2557
+ * @internal
2558
+ * @param apiKey API key from {@link ProtocolsRouterConfig}
2559
+ * @returns True if the API key is considered valid
2560
+ */
2561
+ async validate() {
2562
+ if (!this.validateApiKeyFormat()) {
2563
+ throw new Error("Invalid API key format");
2564
+ }
2565
+ const apiResponse = await this.sendRequest("apiKeyValidation");
2566
+ if (!apiResponse.success) {
2567
+ throw new Error(apiResponse.error || "Failed to validate API key");
2568
+ }
2569
+ return true;
2570
+ }
2571
+ /**
2572
+ *
2573
+ * Validates the format of the API key. Must start with 'sk_' and contain only hexadecimal characters
2574
+ *
2575
+ * @internal
2576
+ * @param apiKey API key from {@link ProtocolsRouterConfig}
2577
+ * @returns
2578
+ */
2579
+ validateApiKeyFormat() {
2580
+ if (!this.apiKey) {
2581
+ return false;
2582
+ }
2583
+ const prefix = "sk_";
2584
+ if (!this.apiKey.startsWith(prefix)) {
2585
+ return false;
2586
+ }
2587
+ const keyPart = this.apiKey.slice(prefix.length);
2588
+ if (keyPart.length < 32 || keyPart.length > 128) {
2589
+ return false;
2590
+ }
2591
+ const hexPattern = /^[0-9a-fA-F]+$/;
2592
+ if (!hexPattern.test(keyPart)) {
2593
+ return false;
2594
+ }
2595
+ return true;
2596
+ }
2597
+ };
2598
+
2317
2599
  // src/index.ts
2318
- var MyceliumSDK = class {
2600
+ var MyceliumSDK = class _MyceliumSDK {
2319
2601
  /**
2320
2602
  * Creates a new SDK instance
2321
2603
  *
@@ -2323,7 +2605,16 @@ var MyceliumSDK = class {
2323
2605
  * @throws Throws if an unsupported wallet provider is given
2324
2606
  * @see MyceliumSDKConfig
2325
2607
  */
2326
- constructor(config) {
2608
+ constructor(config, isPremiumAvailable, apiClient) {
2609
+ /**
2610
+ * Ramp namespace to manage ramp operations. Methods are available on {@link RampNamespace}
2611
+ * @internal
2612
+ * @remarks
2613
+ * If the Coinbase CDP configuration is not provided, the ramp functionality will be disabled.
2614
+ * Calling the respective method will throw an error
2615
+ * @category Tools
2616
+ */
2617
+ this.fundingNamespace = null;
2327
2618
  /**
2328
2619
  * Coinbase CDP instance to Coinbase related and onchain operations using Coinbase CDP API
2329
2620
  * @remarks
@@ -2332,46 +2623,6 @@ var MyceliumSDK = class {
2332
2623
  * @internal
2333
2624
  */
2334
2625
  this.coinbaseCDP = null;
2335
- /**
2336
- * Coinbase CDP configuration methods for ramp operations
2337
- * @public
2338
- * @category Tools
2339
- */
2340
- this.rampConfig = {
2341
- /**
2342
- * Return all supported countries and payment methods for on-ramp by Coinbase CDP
2343
- * @public
2344
- * @category Ramp
2345
- *
2346
- * @returns @see {@link RampConfigResponse} with supported countries and payment methods for top-up
2347
- * @throws If API returned an error
2348
- */
2349
- getTopUpConfig: async () => {
2350
- if (!this.coinbaseCDP) {
2351
- throw new Error(
2352
- "Coinbase CDP is not initialized. Please, provide the configuration in the SDK initialization"
2353
- );
2354
- }
2355
- return await this.coinbaseCDP.getOnRampConfig();
2356
- },
2357
- /**
2358
- * Return all supported countries and payment methods for off-ramp by Coinbase CDP
2359
- * @public
2360
- * @category Ramp
2361
- *
2362
- *
2363
- * @returns @see {@link RampConfigResponse} with supported countries and payment methods for cash out
2364
- * @throws If API returned an error
2365
- */
2366
- getCashOutConfig: async () => {
2367
- if (!this.coinbaseCDP) {
2368
- throw new Error(
2369
- "Coinbase CDP is not initialized. Please, provide the configuration in the SDK initialization"
2370
- );
2371
- }
2372
- return await this.coinbaseCDP.getOffRampConfig();
2373
- }
2374
- };
2375
2626
  this._chainManager = new ChainManager(
2376
2627
  config.chain || {
2377
2628
  chainId: base3.id,
@@ -2379,11 +2630,14 @@ var MyceliumSDK = class {
2379
2630
  bundlerUrl: "https://public.pimlico.io/v2/8453/rpc"
2380
2631
  }
2381
2632
  );
2382
- if (!config.chain) {
2383
- logger.warn(
2384
- "No chain config provided, using default public RPC and Bundler URLs",
2385
- "MyceliumSDK"
2633
+ if (config.protocolsSecurityConfig) {
2634
+ this.protocol = this.selectProtocol(
2635
+ config.protocolsSecurityConfig,
2636
+ isPremiumAvailable,
2637
+ apiClient
2386
2638
  );
2639
+ } else {
2640
+ throw new Error("Protocols router config is required");
2387
2641
  }
2388
2642
  if (config.coinbaseCDPConfig) {
2389
2643
  this.coinbaseCDP = new CoinbaseCDP(
@@ -2392,16 +2646,71 @@ var MyceliumSDK = class {
2392
2646
  config.integratorId,
2393
2647
  this.chainManager
2394
2648
  );
2649
+ this.fundingNamespace = new FundingNamespace(this.coinbaseCDP);
2395
2650
  }
2396
- const protocolsRouterConfig = config.protocolsRouterConfig || {
2397
- riskLevel: "low"
2398
- };
2399
- this.protocol = this.findProtocol(protocolsRouterConfig);
2400
2651
  this.wallet = this.createWalletNamespace(config.walletsConfig);
2652
+ this.protocols = new ProtocolsNamespace(this.protocol);
2653
+ }
2654
+ /**
2655
+ * Initializes the SDK
2656
+ * @param config SDK configuration (networks, wallets, protocol router settings)
2657
+ * @returns SDK instance
2658
+ */
2659
+ static async init(config) {
2660
+ let finalConfig;
2661
+ let isPremiumAvailable = false;
2662
+ if ("apiKey" in config && config.apiKey) {
2663
+ const apiClient = new ApiClient(config.apiKey);
2664
+ isPremiumAvailable = await apiClient.validate();
2665
+ if (isPremiumAvailable) {
2666
+ const apiResponse = await apiClient.sendRequest("config");
2667
+ if (!apiResponse.success) {
2668
+ throw new Error(apiResponse.error || "Failed to get onchain config");
2669
+ }
2670
+ const backendConfig = apiResponse.data;
2671
+ finalConfig = {
2672
+ integratorId: backendConfig.integratorId,
2673
+ walletsConfig: {
2674
+ embeddedWalletConfig: {
2675
+ provider: {
2676
+ type: "privy",
2677
+ providerConfig: {
2678
+ appId: backendConfig.privyAppId,
2679
+ appSecret: backendConfig.privyAppSecret
2680
+ }
2681
+ }
2682
+ },
2683
+ smartWalletConfig: {
2684
+ provider: {
2685
+ type: "default"
2686
+ }
2687
+ }
2688
+ },
2689
+ chain: {
2690
+ chainId: config.chainId || backendConfig.chainId,
2691
+ rpcUrl: backendConfig.rpcUrl,
2692
+ bundlerUrl: backendConfig.bundlerUrl
2693
+ },
2694
+ protocolsSecurityConfig: config.protocolsSecurityConfig,
2695
+ coinbaseCDPConfig: {
2696
+ apiKeyId: backendConfig.coinbaseCdpApiKey,
2697
+ apiKeySecret: backendConfig.coinbaseCdpApiKeySecret
2698
+ }
2699
+ };
2700
+ const sdk2 = new _MyceliumSDK(finalConfig, isPremiumAvailable, apiClient);
2701
+ sdk2.apiClient = apiClient;
2702
+ return sdk2;
2703
+ }
2704
+ }
2705
+ finalConfig = config;
2706
+ const sdk = new _MyceliumSDK(finalConfig, isPremiumAvailable);
2707
+ return sdk;
2401
2708
  }
2402
2709
  /**
2403
2710
  * Returns the chain manager instance for multi-chain operations
2404
2711
  * @public
2712
+ * @remarks
2713
+ * More about methods in {@link ChainManager}
2405
2714
  * @category Tools
2406
2715
  *
2407
2716
  * @returns ChainManager instance of the type {@link ChainManager}
@@ -2409,6 +2718,23 @@ var MyceliumSDK = class {
2409
2718
  get chainManager() {
2410
2719
  return this._chainManager;
2411
2720
  }
2721
+ /**
2722
+ * Returns a funding namespace to manage top ups & cash outs configurations
2723
+ * @public
2724
+ * @remarks
2725
+ * More about methods in {@link FundingNamespace}
2726
+ * @category Tools
2727
+ *
2728
+ * @returns Funding namespace of the type {@link FundingNamespace}
2729
+ */
2730
+ get funding() {
2731
+ if (!this.fundingNamespace) {
2732
+ throw new Error(
2733
+ "Ramp namespace is not initialized. Please, provide the configuration in the SDK initialization"
2734
+ );
2735
+ }
2736
+ return this.fundingNamespace;
2737
+ }
2412
2738
  /**
2413
2739
  * Recommends and initializes a protocol based on router settings
2414
2740
  *
@@ -2416,10 +2742,13 @@ var MyceliumSDK = class {
2416
2742
  * @param config Protocol router configuration (e.g. risk level)
2417
2743
  * @returns Selected protocol object of the type {@link Protocol}
2418
2744
  */
2419
- findProtocol(config) {
2420
- const protocolRouter = new ProtocolRouter(config, this.chainManager);
2421
- const protocol = protocolRouter.recommend();
2422
- protocol.instance.init(this.chainManager);
2745
+ selectProtocol(config, isPremiumAvailable, apiClient) {
2746
+ const protocolRouter = new ProtocolRouter(this.chainManager, isPremiumAvailable);
2747
+ const protocol = protocolRouter.select();
2748
+ if (!config) {
2749
+ throw new Error("Protocols security config is required");
2750
+ }
2751
+ protocol.init(this.chainManager, config, apiClient);
2423
2752
  return protocol;
2424
2753
  }
2425
2754
  /**
@@ -2476,6 +2805,7 @@ var MyceliumSDK = class {
2476
2805
  };
2477
2806
  export {
2478
2807
  DefaultSmartWallet,
2808
+ FundingNamespace,
2479
2809
  MyceliumSDK
2480
2810
  };
2481
2811
  //# sourceMappingURL=index.js.map