@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.cjs CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  DefaultSmartWallet: () => DefaultSmartWallet,
34
+ FundingNamespace: () => FundingNamespace,
34
35
  MyceliumSDK: () => MyceliumSDK
35
36
  });
36
37
  module.exports = __toCommonJS(index_exports);
@@ -381,9 +382,9 @@ var DefaultSmartWallet = class extends SmartWallet {
381
382
  * @param amount Human-readable amount string
382
383
  * @returns Transaction result for the deposit
383
384
  */
384
- async earn(amount) {
385
+ async earn(vaultInfo, amount) {
385
386
  this.chainManager.getSupportedChain();
386
- const depositTransactionResult = this.protocolProvider.deposit(amount, this);
387
+ const depositTransactionResult = this.protocolProvider.deposit(vaultInfo, amount, this);
387
388
  return depositTransactionResult;
388
389
  }
389
390
  /**
@@ -394,13 +395,9 @@ var DefaultSmartWallet = class extends SmartWallet {
394
395
  * @category Earn
395
396
  * @returns Vault balance or `null` if nothing deposited
396
397
  */
397
- async getEarnBalance() {
398
- const depositedVault = await this.protocolProvider.fetchDepositedVaults(this);
399
- if (!depositedVault) {
400
- return null;
401
- }
398
+ async getEarnBalances() {
402
399
  const userAddress = await this.getAddress();
403
- return this.protocolProvider.getBalance(depositedVault, userAddress);
400
+ return this.protocolProvider.getBalances(userAddress);
404
401
  }
405
402
  /**
406
403
  * Withdraws from the selected protocol’s vault
@@ -411,8 +408,8 @@ var DefaultSmartWallet = class extends SmartWallet {
411
408
  * @throws Error if the withdrawal fails
412
409
  * @throws Error a user didn't deposit anything
413
410
  */
414
- async withdraw(amount) {
415
- const withdrawTransactionResult = await this.protocolProvider.withdraw(amount, this);
411
+ async withdraw(vaultInfo, amount) {
412
+ const withdrawTransactionResult = await this.protocolProvider.withdraw(vaultInfo, amount, this);
416
413
  return withdrawTransactionResult;
417
414
  }
418
415
  /**
@@ -449,7 +446,7 @@ var DefaultSmartWallet = class extends SmartWallet {
449
446
  return hash;
450
447
  } catch (error) {
451
448
  throw new Error(
452
- `Failed to send transaction: ${error instanceof Error ? error.message : "Unknown error"}`
449
+ `Failed to send transaction: ${error instanceof Error ? error.message.toString().slice(0, 100) : "Unknown error"}`
453
450
  );
454
451
  }
455
452
  }
@@ -494,7 +491,7 @@ var DefaultSmartWallet = class extends SmartWallet {
494
491
  * Funds the smart wallet with the specified amount of the specified token via Coinbase CDP on-ramp service
495
492
  *
496
493
  * @public
497
- * @category Ramp
494
+ * @category Funding
498
495
  *
499
496
  * @remarks
500
497
  * 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}
@@ -532,7 +529,7 @@ var DefaultSmartWallet = class extends SmartWallet {
532
529
  * Cashout token from smart wallet to fiat currency via Coinbase CDP off-ramp service
533
530
  *
534
531
  * @public
535
- * @category Ramp
532
+ * @category Funding
536
533
  *
537
534
  * @remarks
538
535
  * 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}
@@ -608,6 +605,42 @@ var DefaultSmartWallet = class extends SmartWallet {
608
605
  }
609
606
  };
610
607
 
608
+ // src/ramp/FundingNamespace.ts
609
+ var FundingNamespace = class {
610
+ constructor(coinbaseCDP) {
611
+ this.coinbaseCDP = null;
612
+ if (!coinbaseCDP) {
613
+ throw new Error(
614
+ "Coinbase CDP is not initialized. Please, provide the configuration in the SDK initialization"
615
+ );
616
+ }
617
+ this.coinbaseCDP = coinbaseCDP;
618
+ }
619
+ /**
620
+ * Return all supported countries and payment methods for on-ramp by Coinbase CDP
621
+ * @public
622
+ * @category Funding
623
+ *
624
+ * @returns @see {@link RampConfigResponse} with supported countries and payment methods for top-up
625
+ * @throws If API returned an error
626
+ */
627
+ async getTopUpConfig() {
628
+ return await this.coinbaseCDP.getOnRampConfig();
629
+ }
630
+ /**
631
+ * Return all supported countries and payment methods for off-ramp by Coinbase CDP
632
+ * @public
633
+ * @category Funding
634
+ *
635
+ *
636
+ * @returns @see {@link RampConfigResponse} with supported countries and payment methods for cash out
637
+ * @throws If API returned an error
638
+ */
639
+ async getCashOutConfig() {
640
+ return await this.coinbaseCDP.getOffRampConfig();
641
+ }
642
+ };
643
+
611
644
  // src/tools/ChainManager.ts
612
645
  var import_viem5 = require("viem");
613
646
  var import_account_abstraction2 = require("viem/account-abstraction");
@@ -634,127 +667,6 @@ var chainById = Object.values(viemChains).reduce(
634
667
  {}
635
668
  );
636
669
 
637
- // src/types/logger.ts
638
- var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
639
- LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
640
- LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
641
- LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
642
- LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
643
- return LogLevel2;
644
- })(LogLevel || {});
645
-
646
- // src/tools/Logger.ts
647
- var Logger = class _Logger {
648
- /**
649
- * Create a new logger instance
650
- * @param logLevel Initial log level, defaults to DEBUG
651
- */
652
- constructor(logLevel = 0 /* DEBUG */) {
653
- this.logs = [];
654
- this.maxLogs = 1e3;
655
- this.logLevel = logLevel;
656
- }
657
- /**
658
- * Get singleton instance of the logger
659
- * @param logLevel Optional log level to initialize if instance not yet created
660
- * @returns Logger instance
661
- */
662
- static getInstance(logLevel) {
663
- if (!_Logger.instance) {
664
- _Logger.instance = new _Logger(logLevel);
665
- }
666
- return _Logger.instance;
667
- }
668
- /** Set the log level */
669
- setLogLevel(level) {
670
- this.logLevel = level;
671
- }
672
- /** Get the current log level */
673
- getLogLevel() {
674
- return this.logLevel;
675
- }
676
- /** Internal check if a message should be logged */
677
- shouldLog(level) {
678
- return level >= this.logLevel;
679
- }
680
- /** Format log message into a readable string */
681
- formatMessage(level, message, data, context) {
682
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
683
- const levelName = LogLevel[level];
684
- const contextStr = context ? `[${context}]` : "";
685
- return `${timestamp} ${levelName}${contextStr}: ${message}`;
686
- }
687
- /** Add a log entry and output to console */
688
- addLog(level, message, data, context) {
689
- if (!this.shouldLog(level)) {
690
- return;
691
- }
692
- const logEntry = {
693
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
694
- level,
695
- message,
696
- data,
697
- context
698
- };
699
- this.logs.push(logEntry);
700
- if (this.logs.length > this.maxLogs) {
701
- this.logs = this.logs.slice(-this.maxLogs);
702
- }
703
- const formattedMessage = this.formatMessage(level, message, data, context);
704
- switch (level) {
705
- case 0 /* DEBUG */:
706
- console.debug(`\u{1F50D} ${formattedMessage}`, data || "");
707
- break;
708
- case 1 /* INFO */:
709
- console.info(`\u2139\uFE0F ${formattedMessage}`, data || "");
710
- break;
711
- case 2 /* WARN */:
712
- console.warn(`\u26A0\uFE0F ${formattedMessage}`, data || "");
713
- break;
714
- case 3 /* ERROR */:
715
- console.error(`\u274C ${formattedMessage}`, data || "");
716
- break;
717
- }
718
- }
719
- /** Log a debug message */
720
- debug(message, data, context) {
721
- this.addLog(0 /* DEBUG */, message, data, context);
722
- }
723
- /** Log an info message */
724
- info(message, data, context) {
725
- this.addLog(1 /* INFO */, message, data, context);
726
- }
727
- /** Log a warning message */
728
- warn(message, data, context) {
729
- this.addLog(2 /* WARN */, message, data, context);
730
- }
731
- /** Log an error message */
732
- error(message, data, context) {
733
- this.addLog(3 /* ERROR */, message, data, context);
734
- }
735
- /** Get all logs */
736
- getLogs() {
737
- return [...this.logs];
738
- }
739
- /** Get logs by level */
740
- getLogsByLevel(level) {
741
- return this.logs.filter((log) => log.level === level);
742
- }
743
- /** Clear all logs */
744
- clearLogs() {
745
- this.logs = [];
746
- }
747
- /** Export logs as a JSON string */
748
- exportLogs() {
749
- return JSON.stringify(this.logs, null, 2);
750
- }
751
- /** Set maximum number of logs to retain in memory */
752
- setMaxLogs(max) {
753
- this.maxLogs = max;
754
- }
755
- };
756
- var logger = Logger.getInstance();
757
-
758
670
  // src/tools/ChainManager.ts
759
671
  var ChainManager = class {
760
672
  /**
@@ -810,7 +722,6 @@ var ChainManager = class {
810
722
  if (!bundlerUrl) {
811
723
  throw new Error(`No bundler URL configured for chain ID: ${chainId}`);
812
724
  }
813
- logger.info("Public client setup:", { bundlerUrl, chainId }, "ChainManager");
814
725
  const client = (0, import_viem5.createPublicClient)({
815
726
  chain: this.getChain(chainId),
816
727
  transport: (0, import_viem5.http)(rpcUrl)
@@ -913,32 +824,6 @@ var WalletNamespace = class {
913
824
  constructor(provider) {
914
825
  this.provider = provider;
915
826
  }
916
- /**
917
- * Direct access to the underlying embedded wallet provider
918
- *
919
- * @public
920
- * @category Providers
921
- * @remarks
922
- * Useful when you need advanced functionality beyond the unified namespace. By default, you should use the unified namespace
923
- *
924
- * @returns The configured embedded wallet provider instance
925
- */
926
- get embeddedWalletProvider() {
927
- return this.provider.embeddedWalletProvider;
928
- }
929
- /**
930
- * Direct access to the underlying smart wallet provider
931
- *
932
- * @public
933
- * @category Providers
934
- * @remarks
935
- * Useful when you need advanced functionality beyond the unified namespace. By default, you should use the unified namespace
936
- *
937
- * @returns The configured smart wallet provider instance
938
- */
939
- get smartWalletProvider() {
940
- return this.provider.smartWalletProvider;
941
- }
942
827
  /**
943
828
  * Creates an embedded wallet
944
829
  *
@@ -971,7 +856,7 @@ var WalletNamespace = class {
971
856
  return this.provider.createSmartWallet(params);
972
857
  }
973
858
  /**
974
- * Creates a smart wallet with an embedded wallet as signer
859
+ * A unified a web3 account: creates a smart wallet with an embedded wallet as signer
975
860
  *
976
861
  * @public
977
862
  * @category Creation
@@ -985,11 +870,11 @@ var WalletNamespace = class {
985
870
  * @param params.nonce Optional nonce/salt for deterministic address generation (defaults to 0)
986
871
  * @returns Promise that resolves to the created {@link SmartWallet}
987
872
  */
988
- async createWalletWithEmbeddedSigner(params) {
989
- return this.provider.createWalletWithEmbeddedSigner(params);
873
+ async createAccount(params) {
874
+ return this.provider.createAccount(params);
990
875
  }
991
876
  /**
992
- * Gets a smart wallet using an embedded wallet as the signer
877
+ * Gets a unified web3 account: a smart wallet using an embedded wallet as the signer
993
878
  *
994
879
  * @public
995
880
  * @category Retrieval
@@ -1007,8 +892,8 @@ var WalletNamespace = class {
1007
892
  * @returns Promise that resolves to the {@link SmartWallet}
1008
893
  * @throws Error if the embedded wallet cannot be found
1009
894
  */
1010
- async getSmartWalletWithEmbeddedSigner(params) {
1011
- return this.provider.getSmartWalletWithEmbeddedSigner(params);
895
+ async getAccount(params) {
896
+ return this.provider.getAccount(params);
1012
897
  }
1013
898
  /**
1014
899
  * Gets an existing embedded wallet by ID
@@ -1069,7 +954,7 @@ var DefaultSmartWalletProvider = class extends SmartWalletProvider {
1069
954
  constructor(chainManager, protocol, coinbaseCDP) {
1070
955
  super();
1071
956
  this.chainManager = chainManager;
1072
- this.protocolProvider = protocol.instance;
957
+ this.protocolProvider = protocol;
1073
958
  this.coinbaseCDP = coinbaseCDP;
1074
959
  }
1075
960
  /**
@@ -1164,18 +1049,6 @@ var DefaultSmartWalletProvider = class extends SmartWalletProvider {
1164
1049
  ownerIndex
1165
1050
  );
1166
1051
  }
1167
- /**
1168
- * Funds a wallet via a faucet if supported by the selected chain
1169
- *
1170
- * @internal
1171
- * @category Funding
1172
- * @remarks
1173
- * Placeholder for testnet faucet integration
1174
- *
1175
- * @returns Future transaction hash or provider response
1176
- */
1177
- fundViaFaucet() {
1178
- }
1179
1052
  };
1180
1053
 
1181
1054
  // src/wallet/WalletProvider.ts
@@ -1239,9 +1112,12 @@ var WalletProvider = class {
1239
1112
  * @param params.nonce Optional salt/nonce for deterministic address calculation (defaults to 0)
1240
1113
  * @returns Promise that resolves to the created {@link SmartWallet}
1241
1114
  */
1242
- async createWalletWithEmbeddedSigner(params) {
1115
+ async createAccount(params) {
1243
1116
  const { owners: ownersParam, embeddedWalletIndex, nonce } = params || {};
1244
1117
  const embeddedWallet = await this.embeddedWalletProvider.createWallet();
1118
+ if (!embeddedWallet.walletId) {
1119
+ throw new Error("Failed to create embedded wallet. No wallet ID returned");
1120
+ }
1245
1121
  const account = await embeddedWallet.account();
1246
1122
  let owners;
1247
1123
  if (ownersParam) {
@@ -1251,14 +1127,18 @@ var WalletProvider = class {
1251
1127
  } else {
1252
1128
  owners = [embeddedWallet.address];
1253
1129
  }
1254
- return this.smartWalletProvider.createWallet({
1130
+ const smartWallet = await this.smartWalletProvider.createWallet({
1255
1131
  owners,
1256
1132
  signer: account,
1257
1133
  nonce
1258
1134
  });
1135
+ return {
1136
+ embeddedWalletId: embeddedWallet.walletId,
1137
+ smartWallet
1138
+ };
1259
1139
  }
1260
1140
  /**
1261
- * Gets a smart wallet using an embedded wallet as the signer
1141
+ * Gets a unified web3 account: a smart wallet using an embedded wallet as the signer
1262
1142
  *
1263
1143
  * @internal
1264
1144
  * @remarks
@@ -1275,7 +1155,7 @@ var WalletProvider = class {
1275
1155
  * @returns Promise that resolves to the {@link SmartWallet}
1276
1156
  * @throws Error if the embedded wallet cannot be found
1277
1157
  */
1278
- async getSmartWalletWithEmbeddedSigner(params) {
1158
+ async getAccount(params) {
1279
1159
  const { walletId, deploymentOwners, walletAddress } = params;
1280
1160
  const embeddedWallet = await this.embeddedWalletProvider.getWallet({
1281
1161
  walletId
@@ -1337,8 +1217,7 @@ var WalletProvider = class {
1337
1217
  throw new Error(
1338
1218
  "Either walletAddress or deploymentOwners array must be provided to locate the smart wallet"
1339
1219
  );
1340
- } catch (error) {
1341
- logger.error("Error getting smart wallet", error, "WalletProvider");
1220
+ } catch {
1342
1221
  throw new Error(
1343
1222
  "Either walletAddress or deploymentOwners array must be provided to locate the smart wallet"
1344
1223
  );
@@ -1381,6 +1260,127 @@ var EmbeddedWallet = class {
1381
1260
  }
1382
1261
  };
1383
1262
 
1263
+ // src/types/logger.ts
1264
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
1265
+ LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
1266
+ LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
1267
+ LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
1268
+ LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
1269
+ return LogLevel2;
1270
+ })(LogLevel || {});
1271
+
1272
+ // src/tools/Logger.ts
1273
+ var Logger = class _Logger {
1274
+ /**
1275
+ * Create a new logger instance
1276
+ * @param logLevel Initial log level, defaults to DEBUG
1277
+ */
1278
+ constructor(logLevel = 0 /* DEBUG */) {
1279
+ this.logs = [];
1280
+ this.maxLogs = 1e3;
1281
+ this.logLevel = logLevel;
1282
+ }
1283
+ /**
1284
+ * Get singleton instance of the logger
1285
+ * @param logLevel Optional log level to initialize if instance not yet created
1286
+ * @returns Logger instance
1287
+ */
1288
+ static getInstance(logLevel) {
1289
+ if (!_Logger.instance) {
1290
+ _Logger.instance = new _Logger(logLevel);
1291
+ }
1292
+ return _Logger.instance;
1293
+ }
1294
+ /** Set the log level */
1295
+ setLogLevel(level) {
1296
+ this.logLevel = level;
1297
+ }
1298
+ /** Get the current log level */
1299
+ getLogLevel() {
1300
+ return this.logLevel;
1301
+ }
1302
+ /** Internal check if a message should be logged */
1303
+ shouldLog(level) {
1304
+ return level >= this.logLevel;
1305
+ }
1306
+ /** Format log message into a readable string */
1307
+ formatMessage(level, message, data, context) {
1308
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1309
+ const levelName = LogLevel[level];
1310
+ const contextStr = context ? `[${context}]` : "";
1311
+ return `${timestamp} ${levelName}${contextStr}: ${message}`;
1312
+ }
1313
+ /** Add a log entry and output to console */
1314
+ addLog(level, message, data, context) {
1315
+ if (!this.shouldLog(level)) {
1316
+ return;
1317
+ }
1318
+ const logEntry = {
1319
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1320
+ level,
1321
+ message,
1322
+ data,
1323
+ context
1324
+ };
1325
+ this.logs.push(logEntry);
1326
+ if (this.logs.length > this.maxLogs) {
1327
+ this.logs = this.logs.slice(-this.maxLogs);
1328
+ }
1329
+ const formattedMessage = this.formatMessage(level, message, data, context);
1330
+ switch (level) {
1331
+ case 0 /* DEBUG */:
1332
+ console.debug(`\u{1F50D} ${formattedMessage}`, data || "");
1333
+ break;
1334
+ case 1 /* INFO */:
1335
+ console.info(`\u2139\uFE0F ${formattedMessage}`, data || "");
1336
+ break;
1337
+ case 2 /* WARN */:
1338
+ console.warn(`\u26A0\uFE0F ${formattedMessage}`, data || "");
1339
+ break;
1340
+ case 3 /* ERROR */:
1341
+ console.error(`\u274C ${formattedMessage}`, data || "");
1342
+ break;
1343
+ }
1344
+ }
1345
+ /** Log a debug message */
1346
+ debug(message, data, context) {
1347
+ this.addLog(0 /* DEBUG */, message, data, context);
1348
+ }
1349
+ /** Log an info message */
1350
+ info(message, data, context) {
1351
+ this.addLog(1 /* INFO */, message, data, context);
1352
+ }
1353
+ /** Log a warning message */
1354
+ warn(message, data, context) {
1355
+ this.addLog(2 /* WARN */, message, data, context);
1356
+ }
1357
+ /** Log an error message */
1358
+ error(message, data, context) {
1359
+ this.addLog(3 /* ERROR */, message, data, context);
1360
+ }
1361
+ /** Get all logs */
1362
+ getLogs() {
1363
+ return [...this.logs];
1364
+ }
1365
+ /** Get logs by level */
1366
+ getLogsByLevel(level) {
1367
+ return this.logs.filter((log) => log.level === level);
1368
+ }
1369
+ /** Clear all logs */
1370
+ clearLogs() {
1371
+ this.logs = [];
1372
+ }
1373
+ /** Export logs as a JSON string */
1374
+ exportLogs() {
1375
+ return JSON.stringify(this.logs, null, 2);
1376
+ }
1377
+ /** Set maximum number of logs to retain in memory */
1378
+ setMaxLogs(max) {
1379
+ this.maxLogs = max;
1380
+ }
1381
+ };
1382
+ var logger = Logger.getInstance();
1383
+
1384
1384
  // src/wallet/PrivyWallet.ts
1385
1385
  var PrivyWallet = class extends EmbeddedWallet {
1386
1386
  /**
@@ -1761,14 +1761,14 @@ var SPARK_SSR_ORACLE_ADDRESS = "0x65d946e533748A998B1f0E430803e39A6388f7a1";
1761
1761
  var SPARK_VAULT = [
1762
1762
  {
1763
1763
  id: "sUSDC",
1764
+ protocolId: "spark",
1765
+ name: "sUSDC",
1766
+ type: "stable",
1764
1767
  chain: "base",
1765
1768
  vaultAddress: "0x3128a0f7f0ea68e7b7c9b00afa7e41045828e858",
1766
- depositTokenAddress: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1767
- depositTokenDecimals: 6,
1768
- depositTokenSymbol: "USDC",
1769
- earnTokenAddress: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1770
- earnTokenDecimals: 18,
1771
- earnTokenSymbol: "sUSDC",
1769
+ tokenAddress: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
1770
+ tokenDecimals: 6,
1771
+ tokenSymbol: "USDC",
1772
1772
  metadata: {}
1773
1773
  }
1774
1774
  ];
@@ -1779,6 +1779,7 @@ var RAY = BigInt("1000000000000000000000000000");
1779
1779
  var SparkProtocol = class extends BaseProtocol {
1780
1780
  constructor() {
1781
1781
  super(...arguments);
1782
+ /** All Spark vaults */
1782
1783
  this.allVaults = [];
1783
1784
  }
1784
1785
  /**
@@ -1789,7 +1790,7 @@ var SparkProtocol = class extends BaseProtocol {
1789
1790
  this.chainManager = chainManager;
1790
1791
  this.selectedChainId = chainManager.getSupportedChain();
1791
1792
  this.publicClient = chainManager.getPublicClient(this.selectedChainId);
1792
- this.allVaults = this.getVaults();
1793
+ this.allVaults = SPARK_VAULT;
1793
1794
  }
1794
1795
  /**
1795
1796
  * Get the SSR (Sky Saving Rate) of the Spark protocol
@@ -1819,88 +1820,54 @@ var SparkProtocol = class extends BaseProtocol {
1819
1820
  async getAPY() {
1820
1821
  const ssr = await this.getSSR();
1821
1822
  const apy = Math.exp(Math.log(ssr) * SECONDS_PER_YEAR) - 1;
1822
- return Number((apy * 100).toFixed(2));
1823
- }
1824
- /**
1825
- *
1826
- * Get all vault info from a Spark protocol
1827
- * @returns The list of vaults
1828
- */
1829
- getVaults() {
1830
- return SPARK_VAULT;
1823
+ return apy;
1831
1824
  }
1832
1825
  /**
1833
- * Get the best available Spark vault
1834
- * @returns The top-ranked Spark vault
1826
+ * Get the best available Spark vaults
1827
+ * @remarks Currently, the vault is only one and relates to sUSDC. Currently return only one stable vault
1828
+ * @returns Best Spark vaults in 2 groups: stable and non-stable
1835
1829
  * @throws Error if no vaults found
1836
1830
  */
1837
- async getBestVault() {
1831
+ async getBestVaults() {
1838
1832
  if (this.allVaults.length === 0) {
1839
1833
  throw new Error("No vaults found");
1840
1834
  }
1841
1835
  const selectedVault = this.allVaults[0];
1842
1836
  selectedVault.metadata.apy = await this.getAPY();
1843
- return selectedVault;
1844
- }
1845
- /**
1846
- * Fetch a vault where the user previously deposited funds
1847
- * @param smartWallet Smart wallet to inspect
1848
- * @returns The vault with user deposits, or null if none found
1849
- */
1850
- async fetchDepositedVaults(smartWallet) {
1851
- let depositedVault = void 0;
1852
- const userAddress = await smartWallet.getAddress();
1853
- for (const vault of this.allVaults) {
1854
- const balance = await this.getBalance(vault, userAddress);
1855
- if (parseInt(balance.depositedAmount) > 0) {
1856
- depositedVault = vault;
1857
- }
1858
- }
1859
- if (depositedVault) {
1860
- depositedVault.metadata.apy = await this.getAPY();
1861
- }
1862
- logger.info("Deposited vaults:", { depositedVault }, "SparkProtocol");
1863
- return depositedVault || null;
1837
+ return {
1838
+ stable: [selectedVault],
1839
+ nonStable: []
1840
+ };
1864
1841
  }
1865
1842
  /**
1866
1843
  * Deposit funds into a Spark vault
1844
+ * @param vaultInfo Vault information
1867
1845
  * @param amount Amount to deposit (human-readable)
1868
1846
  * @param smartWallet Smart wallet instance to use
1869
1847
  * @returns Transaction result with hash
1870
1848
  */
1871
- async deposit(amount, smartWallet) {
1872
- const depositedVault = await this.fetchDepositedVaults(smartWallet);
1873
- let vaultInfoToDeposit;
1874
- logger.info("Previously deposited vault:", { depositedVault }, "SparkProtocol");
1875
- if (depositedVault) {
1876
- vaultInfoToDeposit = depositedVault;
1877
- } else {
1878
- vaultInfoToDeposit = await this.getBestVault();
1879
- logger.info("Best vault that found:", { bestVault: vaultInfoToDeposit }, "SparkProtocol");
1880
- }
1849
+ async deposit(vaultInfo, amount, smartWallet) {
1881
1850
  const owner = await smartWallet.getAddress();
1882
- const assets = (0, import_viem11.parseUnits)(amount, vaultInfoToDeposit.depositTokenDecimals);
1883
- logger.info("Raw deposit amount:", { amount, assets }, "SparkProtocol");
1851
+ const assets = (0, import_viem11.parseUnits)(amount, vaultInfo.tokenDecimals);
1884
1852
  const allowance = await this.checkAllowance(
1885
- vaultInfoToDeposit.depositTokenAddress,
1886
- vaultInfoToDeposit.vaultAddress,
1853
+ vaultInfo.tokenAddress,
1854
+ vaultInfo.vaultAddress,
1887
1855
  owner,
1888
1856
  this.selectedChainId
1889
1857
  );
1890
- logger.info("Current vault contract allowance:", { allowance }, "SparkProtocol");
1891
1858
  const ops = [];
1892
1859
  if (allowance < assets) {
1893
1860
  ops.push({
1894
- to: vaultInfoToDeposit.depositTokenAddress,
1861
+ to: vaultInfo.tokenAddress,
1895
1862
  data: (0, import_viem11.encodeFunctionData)({
1896
1863
  abi: import_viem11.erc20Abi,
1897
1864
  functionName: "approve",
1898
- args: [vaultInfoToDeposit.vaultAddress, assets]
1865
+ args: [vaultInfo.vaultAddress, assets]
1899
1866
  })
1900
1867
  });
1901
1868
  }
1902
1869
  ops.push({
1903
- to: vaultInfoToDeposit.vaultAddress,
1870
+ to: vaultInfo.vaultAddress,
1904
1871
  data: (0, import_viem11.encodeFunctionData)({
1905
1872
  abi: SPARK_VAULT_ABI,
1906
1873
  functionName: "deposit",
@@ -1912,23 +1879,19 @@ var SparkProtocol = class extends BaseProtocol {
1912
1879
  }
1913
1880
  /**
1914
1881
  * Withdraw funds from a Spark vault
1915
- * @param amountInUnderlying Amount in base token units (or undefined to withdraw all)
1882
+ * @param vaultInfo Vault information
1883
+ * @param amount Amount in base token units (or undefined to withdraw all)
1916
1884
  * @param smartWallet Smart wallet instance to withdraw from
1917
1885
  * @returns Transaction result with hash
1918
1886
  * @throws Error if no deposited vault found
1919
1887
  */
1920
- async withdraw(amountInUnderlying, smartWallet) {
1921
- const depositedVault = await this.fetchDepositedVaults(smartWallet);
1922
- if (!depositedVault) {
1923
- throw new Error("No vault found to withdraw from");
1924
- }
1888
+ async withdraw(vaultInfo, amount, smartWallet) {
1925
1889
  const owner = await smartWallet.getAddress();
1926
1890
  let withdrawData;
1927
- if (amountInUnderlying) {
1928
- const assets = (0, import_viem11.parseUnits)(amountInUnderlying, depositedVault.depositTokenDecimals);
1929
- logger.info("Withdraw amount:", { amountInUnderlying, assets }, "SparkProtocol");
1891
+ if (amount) {
1892
+ const assets = (0, import_viem11.parseUnits)(amount, vaultInfo.tokenDecimals);
1930
1893
  withdrawData = {
1931
- to: depositedVault.vaultAddress,
1894
+ to: vaultInfo.vaultAddress,
1932
1895
  data: (0, import_viem11.encodeFunctionData)({
1933
1896
  abi: SPARK_VAULT_ABI,
1934
1897
  functionName: "withdraw",
@@ -1936,10 +1899,9 @@ var SparkProtocol = class extends BaseProtocol {
1936
1899
  })
1937
1900
  };
1938
1901
  } else {
1939
- const maxShares = await this.getMaxRedeemableShares(depositedVault, owner);
1940
- logger.info("Withdrawing all funds:", { maxShares }, "SparkProtocol");
1902
+ const maxShares = await this.getMaxRedeemableShares(vaultInfo, owner);
1941
1903
  withdrawData = {
1942
- to: depositedVault.vaultAddress,
1904
+ to: vaultInfo.vaultAddress,
1943
1905
  data: (0, import_viem11.encodeFunctionData)({
1944
1906
  abi: SPARK_VAULT_ABI,
1945
1907
  functionName: "redeem",
@@ -1948,7 +1910,6 @@ var SparkProtocol = class extends BaseProtocol {
1948
1910
  };
1949
1911
  }
1950
1912
  const hash = await smartWallet.send(withdrawData, this.selectedChainId);
1951
- logger.info("Withdraw transaction sent:", { hash }, "SparkProtocol");
1952
1913
  return { success: true, hash };
1953
1914
  }
1954
1915
  /**
@@ -1971,14 +1932,15 @@ var SparkProtocol = class extends BaseProtocol {
1971
1932
  }
1972
1933
  /**
1973
1934
  * Get amount that a wallet has deposited in a vault
1974
- * @param vaultInfo Vault information
1975
1935
  * @param walletAddress Wallet address to check
1976
- * @returns Object containing shares and deposited amount
1936
+ * @returns Array of vault balances with vaults info
1977
1937
  */
1978
- async getBalance(vaultInfo, walletAddress) {
1938
+ async getBalances(walletAddress) {
1979
1939
  if (!this.publicClient) {
1980
1940
  throw new Error("Public client not initialized");
1981
1941
  }
1942
+ const vaultInfo = SPARK_VAULT[0];
1943
+ vaultInfo.metadata.apy = await this.getAPY();
1982
1944
  const shares = await this.publicClient.readContract({
1983
1945
  address: vaultInfo.vaultAddress,
1984
1946
  abi: SPARK_VAULT_ABI,
@@ -1986,7 +1948,7 @@ var SparkProtocol = class extends BaseProtocol {
1986
1948
  args: [walletAddress]
1987
1949
  });
1988
1950
  if (shares === 0n) {
1989
- return { shares: "0", depositedAmount: "0", vaultInfo };
1951
+ return [{ balance: null, vaultInfo }];
1990
1952
  }
1991
1953
  const assets = await this.publicClient.readContract({
1992
1954
  address: vaultInfo.vaultAddress,
@@ -1994,11 +1956,12 @@ var SparkProtocol = class extends BaseProtocol {
1994
1956
  functionName: "convertToAssets",
1995
1957
  args: [shares]
1996
1958
  });
1997
- return {
1998
- shares: (0, import_viem11.formatUnits)(shares, vaultInfo.earnTokenDecimals),
1999
- depositedAmount: (0, import_viem11.formatUnits)(assets, vaultInfo.depositTokenDecimals),
2000
- vaultInfo
2001
- };
1959
+ return [
1960
+ {
1961
+ balance: (0, import_viem11.formatUnits)(assets, vaultInfo.tokenDecimals),
1962
+ vaultInfo
1963
+ }
1964
+ ];
2002
1965
  }
2003
1966
  };
2004
1967
 
@@ -2010,59 +1973,233 @@ var availableProtocols = [
2010
1973
  name: "Spark",
2011
1974
  website: "https://spark.fi/",
2012
1975
  logo: "/logos/spark.png",
2013
- supportedChains: [1, 8453, 42161],
1976
+ supportedChains: [8453],
2014
1977
  riskLevel: "low",
2015
- isPremium: false
1978
+ isActive: true
2016
1979
  },
2017
1980
  instance: new SparkProtocol()
2018
1981
  }
2019
1982
  ];
2020
1983
 
2021
- // src/tools/ApiKeysValidator.ts
2022
- var ApiKeysValidator = class {
2023
- // TODO: Implement the validation logic
1984
+ // src/protocols/implementations/ProxyProtocol.ts
1985
+ var import_viem12 = require("viem");
1986
+ var ProxyProtocol = class extends BaseProtocol {
2024
1987
  /**
2025
- * Validates whether the provided API key is valid
2026
- *
2027
- * @internal
2028
- * @param apiKey API key from {@link ProtocolsRouterConfig}
2029
- * @returns True if the API key is considered valid
1988
+ * Initialize the Spark protocol with the provided chain manager
1989
+ * @param chainManager Chain manager instance used for network operations
2030
1990
  */
2031
- validate(apiKey) {
2032
- logger.info("Validating api key...", apiKey, "ApiKeysValidator");
2033
- return true;
2034
- }
2035
- };
2036
-
2037
- // src/router/base/ProtocolRouterBase.ts
2038
- var ProtocolRouterBase = class {
2039
- /**
2040
- * Initialize a base protocol router
2041
- * @param riskLevel Risk level required by the integrator
2042
- * @param chainManager Chain manager instance for network operations
2043
- * @param minApy Optional minimum APY filter
2044
- * @param apiKey Optional API key for premium protocol access
2045
- */
2046
- constructor(riskLevel, chainManager, minApy, apiKey) {
2047
- // TODO: Add an API key validation
2048
- /** API key validator instance */
2049
- this.apiKeyValidator = new ApiKeysValidator();
2050
- this.riskLevel = riskLevel;
2051
- this.minApy = minApy;
2052
- this.apiKey = apiKey;
1991
+ async init(chainManager, protocolsSecurityConfig, apiClient) {
2053
1992
  this.chainManager = chainManager;
1993
+ this.selectedChainId = chainManager.getSupportedChain();
1994
+ this.publicClient = chainManager.getPublicClient(this.selectedChainId);
1995
+ this.apiClient = apiClient;
1996
+ this.protocolsSecurityConfig = protocolsSecurityConfig;
1997
+ }
1998
+ /**
1999
+ * Log a vault-related operation after deposit or withdraw funds
2000
+ * @param userAddress Address of the user who performed the operation
2001
+ * @param hash Hash of the operation
2002
+ * @param vaultInfo Information about the vault where the operation was performed
2003
+ * @param chainId Chain ID where the operation was performed
2004
+ * @param amount Amount of the operation
2005
+ * @param operationType Type of the operation
2006
+ * @param operationStatus Status of the operation
2007
+ */
2008
+ async logOperation(userAddress, hash, vaultInfo, chainId, amount, operationType, operationStatus) {
2009
+ const apiResponse = await this.apiClient.sendRequest("log", void 0, void 0, {
2010
+ userAddress,
2011
+ protocolId: vaultInfo.protocolId,
2012
+ vaultAddress: vaultInfo.vaultAddress,
2013
+ transactionHash: hash,
2014
+ chainId: chainId.toString(),
2015
+ amount,
2016
+ status: operationStatus,
2017
+ operationType
2018
+ });
2019
+ if (!apiResponse.success) {
2020
+ throw new Error(
2021
+ apiResponse.error || `Failed to log operation: ${operationType} for vault: ${vaultInfo}`
2022
+ );
2023
+ }
2024
+ }
2025
+ /**
2026
+ * Get the best vaults to deposit funds
2027
+ * @param stableVaultsLimit Limit of stable vaults to get. Optional, default is 1
2028
+ * @param nonStableVaultsLimit Limit of non-stable vaults to get. Optional, default is 1
2029
+ * @returns Best vaults to deposit funds in 2 groups: stable and non-stable
2030
+ */
2031
+ async getBestVaults(stableVaultsLimit = 1, nonStableVaultsLimit = 1) {
2032
+ const pathParams = {
2033
+ risk_level: this.protocolsSecurityConfig.riskLevel,
2034
+ chain_id: this.selectedChainId.toString(),
2035
+ stable_vaults_limit: stableVaultsLimit.toString(),
2036
+ non_stable_vaults_limit: nonStableVaultsLimit.toString()
2037
+ };
2038
+ const apiResponse = await this.apiClient.sendRequest("vaults", pathParams);
2039
+ if (!apiResponse.success) {
2040
+ throw new Error(apiResponse.error || "Failed to get best vaults");
2041
+ }
2042
+ const vaults = apiResponse.data;
2043
+ return {
2044
+ stable: vaults.stableVaults.map((vault) => {
2045
+ return {
2046
+ ...vault,
2047
+ metadata: {
2048
+ apy: vault.metadata?.apy,
2049
+ poolTvlUsd: vault.metadata?.poolTvlUsd
2050
+ }
2051
+ };
2052
+ }),
2053
+ nonStable: vaults.nonStableVaults.map((vault) => {
2054
+ return {
2055
+ ...vault,
2056
+ metadata: {
2057
+ apy: vault.metadata?.apy,
2058
+ poolTvlUsd: vault.metadata?.poolTvlUsd
2059
+ }
2060
+ };
2061
+ })
2062
+ };
2063
+ }
2064
+ /**
2065
+ * Deposit funds to a provided vault
2066
+ * @param vaultInfo Information about the vault to deposit funds to
2067
+ * @param amount Amount of funds to deposit
2068
+ * @param smartWallet Smart wallet to use for the deposit
2069
+ * @returns Result of the deposit transaction
2070
+ */
2071
+ async deposit(vaultInfo, amount, smartWallet) {
2072
+ const currentAddress = await smartWallet.getAddress();
2073
+ const operationsCallData = [];
2074
+ const depositTokenDecimals = vaultInfo.tokenDecimals;
2075
+ const depositTokenAddress = vaultInfo.tokenAddress;
2076
+ const vaultAddress = vaultInfo.vaultAddress;
2077
+ const rawDepositAmount = (0, import_viem12.parseUnits)(amount, depositTokenDecimals);
2078
+ const allowance = await this.checkAllowance(
2079
+ depositTokenAddress,
2080
+ vaultAddress,
2081
+ currentAddress,
2082
+ this.selectedChainId
2083
+ );
2084
+ if (allowance < rawDepositAmount) {
2085
+ const approveData = {
2086
+ to: depositTokenAddress,
2087
+ data: (0, import_viem12.encodeFunctionData)({
2088
+ abi: import_viem12.erc20Abi,
2089
+ functionName: "approve",
2090
+ args: [vaultAddress, rawDepositAmount]
2091
+ })
2092
+ };
2093
+ operationsCallData.push(approveData);
2094
+ }
2095
+ if (!vaultInfo.protocolId) {
2096
+ throw new Error("Vault protocol ID is required");
2097
+ }
2098
+ const apiResponse = await this.apiClient.sendRequest(
2099
+ "deposit",
2100
+ void 0,
2101
+ vaultInfo.protocolId,
2102
+ {
2103
+ vaultInfo,
2104
+ amount: amount.toString(),
2105
+ chainId: this.selectedChainId.toString()
2106
+ }
2107
+ );
2108
+ if (!apiResponse.success) {
2109
+ throw new Error(apiResponse.error || "Failed to receive deposit operations call data");
2110
+ }
2111
+ const receivedOperationsCallData = apiResponse.data;
2112
+ operationsCallData.push(receivedOperationsCallData);
2113
+ const hash = await smartWallet.sendBatch(operationsCallData, this.selectedChainId);
2114
+ const operationStatus = hash ? "completed" : "failed";
2115
+ this.logOperation(
2116
+ currentAddress,
2117
+ hash,
2118
+ vaultInfo,
2119
+ this.selectedChainId,
2120
+ amount,
2121
+ "deposit",
2122
+ operationStatus
2123
+ );
2124
+ return { hash, success: true };
2125
+ }
2126
+ /**
2127
+ * Withdraw funds from a provided vault
2128
+ * @param vaultInfo Information about the vault to withdraw funds from
2129
+ * @param amount Amount of funds to withdraw
2130
+ * @param smartWallet Smart wallet to use for the withdrawal
2131
+ * @returns Result of the withdrawal transaction
2132
+ */
2133
+ async withdraw(vaultInfo, amount, smartWallet) {
2134
+ const currentAddress = await smartWallet.getAddress();
2135
+ const earningBalances = await smartWallet.getEarnBalances();
2136
+ if (!earningBalances) {
2137
+ throw new Error("No earning balances found");
2138
+ }
2139
+ const earningBalance = earningBalances.find((balance) => balance.vaultInfo.id === vaultInfo.id);
2140
+ if (!earningBalance) {
2141
+ throw new Error("No earning balance found");
2142
+ }
2143
+ const balanceInfo = earningBalance.balance;
2144
+ const amountToWithdraw = amount ? amount : balanceInfo.currentBalance;
2145
+ const apiResponse = await this.apiClient.sendRequest(
2146
+ "withdraw",
2147
+ void 0,
2148
+ vaultInfo.protocolId,
2149
+ {
2150
+ vaultInfo,
2151
+ amount: amountToWithdraw,
2152
+ chainId: this.selectedChainId.toString()
2153
+ }
2154
+ );
2155
+ if (!apiResponse.success) {
2156
+ throw new Error(apiResponse.error || "Failed to receive withdraw operations call data");
2157
+ }
2158
+ const withdrawOperationCallData = apiResponse.data;
2159
+ const hash = await smartWallet.send(withdrawOperationCallData, this.selectedChainId);
2160
+ const operationStatus = hash ? "completed" : "failed";
2161
+ this.logOperation(
2162
+ currentAddress,
2163
+ hash,
2164
+ vaultInfo,
2165
+ this.selectedChainId,
2166
+ amountToWithdraw,
2167
+ "withdrawal",
2168
+ operationStatus
2169
+ );
2170
+ return { hash, success: true };
2171
+ }
2172
+ /**
2173
+ * Get the balances of a user by a provided address
2174
+ * @param walletAddress Address of the user to get the balances of
2175
+ * @param protocolId Protocol ID to get the balances for. Optional, default is undefined
2176
+ * @returns Balances of the user in the protocol vaults
2177
+ */
2178
+ async getBalances(walletAddress, protocolId) {
2179
+ const pathParams = {
2180
+ chain_id: this.selectedChainId.toString(),
2181
+ protocol_id: protocolId || "",
2182
+ userAddress: walletAddress
2183
+ };
2184
+ const apiResponse = await this.apiClient.sendRequest("balances", pathParams);
2185
+ if (!apiResponse.success) {
2186
+ throw new Error(apiResponse.error || "Failed to get balances");
2187
+ }
2188
+ const balances = apiResponse.data;
2189
+ return balances;
2054
2190
  }
2055
2191
  };
2056
2192
 
2057
2193
  // src/router/ProtocolRouter.ts
2058
- var ProtocolRouter = class extends ProtocolRouterBase {
2194
+ var ProtocolRouter = class {
2059
2195
  /**
2060
2196
  * Initialize the protocol router
2061
2197
  * @param config Router configuration including risk level, min APY, and optional API key
2062
2198
  * @param chainManager Chain manager instance for network validation
2063
2199
  */
2064
- constructor(config, chainManager) {
2065
- super(config.riskLevel, chainManager, config.minApy, config.apiKey);
2200
+ constructor(chainManager, isApiKeyValid) {
2201
+ this.chainManager = chainManager;
2202
+ this.isApiKeyValid = isApiKeyValid;
2066
2203
  }
2067
2204
  /**
2068
2205
  * Get all protocols available for the current configuration
@@ -2070,13 +2207,9 @@ var ProtocolRouter = class extends ProtocolRouterBase {
2070
2207
  * Includes all non-premium protocols and premium protocols if the API key is valid
2071
2208
  * @returns Array of available protocol definitions
2072
2209
  */
2073
- getProtocols() {
2074
- const isKeyValid = this.apiKeyValidator.validate(this.apiKey);
2210
+ getActivePublicProtocols() {
2075
2211
  const allAvailableProtocols = availableProtocols.filter((protocol) => {
2076
- if (!protocol.info.isPremium) {
2077
- return true;
2078
- }
2079
- return protocol.info.isPremium && isKeyValid;
2212
+ return protocol.info.isActive;
2080
2213
  });
2081
2214
  return allAvailableProtocols;
2082
2215
  }
@@ -2101,18 +2234,20 @@ var ProtocolRouter = class extends ProtocolRouterBase {
2101
2234
  * @throws Error if no protocols are available for the current risk level
2102
2235
  * @returns Protocol instance considered the best match
2103
2236
  */
2104
- recommend() {
2105
- const protocols = this.getProtocols();
2237
+ select() {
2238
+ if (this.isApiKeyValid) {
2239
+ return new ProxyProtocol();
2240
+ }
2241
+ const protocols = this.getActivePublicProtocols();
2106
2242
  const eligibleProtocols = protocols.filter((protocol) => {
2107
- const riskMatches = protocol.info.riskLevel === this.riskLevel;
2108
2243
  const isSupportedChain = this.isProtocolSupportedChain(protocol.info.supportedChains);
2109
- return riskMatches && isSupportedChain;
2244
+ return isSupportedChain;
2110
2245
  });
2111
2246
  if (eligibleProtocols.length === 0) {
2112
- throw new Error(`No protocols available for risk level: ${this.riskLevel}`);
2247
+ throw new Error(`No protocols available`);
2113
2248
  }
2114
2249
  const bestProtocol = eligibleProtocols[0];
2115
- return bestProtocol;
2250
+ return bestProtocol.instance;
2116
2251
  }
2117
2252
  };
2118
2253
 
@@ -2332,8 +2467,161 @@ var CoinbaseCDP = class {
2332
2467
  }
2333
2468
  };
2334
2469
 
2470
+ // src/protocols/ProtocolsNamespace.ts
2471
+ var ProtocolsNamespace = class {
2472
+ constructor(protocol) {
2473
+ this.protocol = protocol;
2474
+ }
2475
+ /**
2476
+ * Find the best vaults for protocols that were selected based on integrator's settings
2477
+ *
2478
+ * @returns Best vaults for protocols that were selected based on integrator's settings
2479
+ */
2480
+ async getBestVaults(stableVaultsLimit = 1, nonStableVaultsLimit = 1) {
2481
+ return await this.protocol.getBestVaults(stableVaultsLimit, nonStableVaultsLimit);
2482
+ }
2483
+ };
2484
+
2485
+ // src/constants/general.ts
2486
+ var BACKEND_HOSTNAME = "http://localhost:3000";
2487
+
2488
+ // src/tools/ApiClient.ts
2489
+ var import_axios2 = __toESM(require("axios"), 1);
2490
+ var ApiClient = class {
2491
+ constructor(apiKey) {
2492
+ this.client = import_axios2.default.create({
2493
+ baseURL: BACKEND_HOSTNAME
2494
+ });
2495
+ /** URL settings for the endpoint: get the best vaults to deposit funds */
2496
+ this.bestVaultUrlSettings = {
2497
+ method: "GET",
2498
+ path: "api/v1/public/protocols/best"
2499
+ };
2500
+ /** URL settings for the endpoint: deposit funds to a provided vault */
2501
+ this.depositUrlSettings = {
2502
+ method: "POST",
2503
+ path: "api/v1/public/protocols/details/:protocolId/deposit"
2504
+ };
2505
+ /** URL settings for the endpoint: log a vault-related operation after deposit or withdraw funds */
2506
+ this.logOperationSettings = {
2507
+ method: "POST",
2508
+ path: "api/v1/public/log/operation"
2509
+ };
2510
+ /** URL settings for the endpoint: withdraw funds from a provided vault */
2511
+ this.withdrawUrlSettings = {
2512
+ method: "POST",
2513
+ path: "api/v1/public/protocols/details/:protocolId/withdraw"
2514
+ };
2515
+ /** URL settings for the endpoint: get the balances of a user by a provided address */
2516
+ this.balancesUrlSettings = {
2517
+ method: "GET",
2518
+ path: "api/v1/public/user/:userAddress/balances"
2519
+ };
2520
+ /** URL settings for the endpoint: validate the API key */
2521
+ this.apiKeyValidUrlSettings = {
2522
+ method: "GET",
2523
+ path: "api/v1/public/valid"
2524
+ };
2525
+ /** URL settings for the endpoint: get the config for services */
2526
+ this.configUrlSettings = {
2527
+ method: "GET",
2528
+ path: "api/v1/public/config"
2529
+ };
2530
+ /** URL settings mapping with operation types */
2531
+ this.operationTypeToUrlSettings = {
2532
+ deposit: this.depositUrlSettings,
2533
+ withdraw: this.withdrawUrlSettings,
2534
+ log: this.logOperationSettings,
2535
+ vaults: this.bestVaultUrlSettings,
2536
+ balances: this.balancesUrlSettings,
2537
+ apiKeyValidation: this.apiKeyValidUrlSettings,
2538
+ config: this.configUrlSettings
2539
+ };
2540
+ this.apiKey = apiKey;
2541
+ if (!this.validateApiKeyFormat()) {
2542
+ throw new Error("Invalid API key format");
2543
+ }
2544
+ }
2545
+ /**
2546
+ * Send a request to the backend API
2547
+ * @param path Path of the endpoint to send the request to
2548
+ * @param method Method of the request
2549
+ * @param body Body of the request
2550
+ * @returns Response from the backend API
2551
+ */
2552
+ async sendRequest(operationType, params, protocolId, body) {
2553
+ const { path, method } = this.operationTypeToUrlSettings[operationType];
2554
+ let requestPath = path;
2555
+ if (protocolId) {
2556
+ requestPath = requestPath.replace(":protocolId", protocolId);
2557
+ }
2558
+ if (params?.userAddress) {
2559
+ requestPath = requestPath.replace(":userAddress", params.userAddress);
2560
+ delete params.userAddress;
2561
+ }
2562
+ const urlParams = new URLSearchParams(params).toString();
2563
+ if (urlParams) {
2564
+ requestPath += `?${urlParams}`;
2565
+ }
2566
+ const response = await this.client.request({
2567
+ method,
2568
+ url: requestPath,
2569
+ data: body,
2570
+ headers: { Authorization: `Bearer ${this.apiKey}`, "Content-Type": "application/json" }
2571
+ });
2572
+ if (response.status !== 200) {
2573
+ throw new Error(`Failed to send request to ${path}`);
2574
+ }
2575
+ const apiResponse = response.data;
2576
+ return apiResponse;
2577
+ }
2578
+ /**
2579
+ * Validates whether the provided API key is valid
2580
+ *
2581
+ * @internal
2582
+ * @param apiKey API key from {@link ProtocolsRouterConfig}
2583
+ * @returns True if the API key is considered valid
2584
+ */
2585
+ async validate() {
2586
+ if (!this.validateApiKeyFormat()) {
2587
+ throw new Error("Invalid API key format");
2588
+ }
2589
+ const apiResponse = await this.sendRequest("apiKeyValidation");
2590
+ if (!apiResponse.success) {
2591
+ throw new Error(apiResponse.error || "Failed to validate API key");
2592
+ }
2593
+ return true;
2594
+ }
2595
+ /**
2596
+ *
2597
+ * Validates the format of the API key. Must start with 'sk_' and contain only hexadecimal characters
2598
+ *
2599
+ * @internal
2600
+ * @param apiKey API key from {@link ProtocolsRouterConfig}
2601
+ * @returns
2602
+ */
2603
+ validateApiKeyFormat() {
2604
+ if (!this.apiKey) {
2605
+ return false;
2606
+ }
2607
+ const prefix = "sk_";
2608
+ if (!this.apiKey.startsWith(prefix)) {
2609
+ return false;
2610
+ }
2611
+ const keyPart = this.apiKey.slice(prefix.length);
2612
+ if (keyPart.length < 32 || keyPart.length > 128) {
2613
+ return false;
2614
+ }
2615
+ const hexPattern = /^[0-9a-fA-F]+$/;
2616
+ if (!hexPattern.test(keyPart)) {
2617
+ return false;
2618
+ }
2619
+ return true;
2620
+ }
2621
+ };
2622
+
2335
2623
  // src/index.ts
2336
- var MyceliumSDK = class {
2624
+ var MyceliumSDK = class _MyceliumSDK {
2337
2625
  /**
2338
2626
  * Creates a new SDK instance
2339
2627
  *
@@ -2341,7 +2629,16 @@ var MyceliumSDK = class {
2341
2629
  * @throws Throws if an unsupported wallet provider is given
2342
2630
  * @see MyceliumSDKConfig
2343
2631
  */
2344
- constructor(config) {
2632
+ constructor(config, isPremiumAvailable, apiClient) {
2633
+ /**
2634
+ * Ramp namespace to manage ramp operations. Methods are available on {@link RampNamespace}
2635
+ * @internal
2636
+ * @remarks
2637
+ * If the Coinbase CDP configuration is not provided, the ramp functionality will be disabled.
2638
+ * Calling the respective method will throw an error
2639
+ * @category Tools
2640
+ */
2641
+ this.fundingNamespace = null;
2345
2642
  /**
2346
2643
  * Coinbase CDP instance to Coinbase related and onchain operations using Coinbase CDP API
2347
2644
  * @remarks
@@ -2350,46 +2647,6 @@ var MyceliumSDK = class {
2350
2647
  * @internal
2351
2648
  */
2352
2649
  this.coinbaseCDP = null;
2353
- /**
2354
- * Coinbase CDP configuration methods for ramp operations
2355
- * @public
2356
- * @category Tools
2357
- */
2358
- this.rampConfig = {
2359
- /**
2360
- * Return all supported countries and payment methods for on-ramp by Coinbase CDP
2361
- * @public
2362
- * @category Ramp
2363
- *
2364
- * @returns @see {@link RampConfigResponse} with supported countries and payment methods for top-up
2365
- * @throws If API returned an error
2366
- */
2367
- getTopUpConfig: async () => {
2368
- if (!this.coinbaseCDP) {
2369
- throw new Error(
2370
- "Coinbase CDP is not initialized. Please, provide the configuration in the SDK initialization"
2371
- );
2372
- }
2373
- return await this.coinbaseCDP.getOnRampConfig();
2374
- },
2375
- /**
2376
- * Return all supported countries and payment methods for off-ramp by Coinbase CDP
2377
- * @public
2378
- * @category Ramp
2379
- *
2380
- *
2381
- * @returns @see {@link RampConfigResponse} with supported countries and payment methods for cash out
2382
- * @throws If API returned an error
2383
- */
2384
- getCashOutConfig: async () => {
2385
- if (!this.coinbaseCDP) {
2386
- throw new Error(
2387
- "Coinbase CDP is not initialized. Please, provide the configuration in the SDK initialization"
2388
- );
2389
- }
2390
- return await this.coinbaseCDP.getOffRampConfig();
2391
- }
2392
- };
2393
2650
  this._chainManager = new ChainManager(
2394
2651
  config.chain || {
2395
2652
  chainId: import_chains7.base.id,
@@ -2397,11 +2654,14 @@ var MyceliumSDK = class {
2397
2654
  bundlerUrl: "https://public.pimlico.io/v2/8453/rpc"
2398
2655
  }
2399
2656
  );
2400
- if (!config.chain) {
2401
- logger.warn(
2402
- "No chain config provided, using default public RPC and Bundler URLs",
2403
- "MyceliumSDK"
2657
+ if (config.protocolsSecurityConfig) {
2658
+ this.protocol = this.selectProtocol(
2659
+ config.protocolsSecurityConfig,
2660
+ isPremiumAvailable,
2661
+ apiClient
2404
2662
  );
2663
+ } else {
2664
+ throw new Error("Protocols router config is required");
2405
2665
  }
2406
2666
  if (config.coinbaseCDPConfig) {
2407
2667
  this.coinbaseCDP = new CoinbaseCDP(
@@ -2410,16 +2670,71 @@ var MyceliumSDK = class {
2410
2670
  config.integratorId,
2411
2671
  this.chainManager
2412
2672
  );
2673
+ this.fundingNamespace = new FundingNamespace(this.coinbaseCDP);
2413
2674
  }
2414
- const protocolsRouterConfig = config.protocolsRouterConfig || {
2415
- riskLevel: "low"
2416
- };
2417
- this.protocol = this.findProtocol(protocolsRouterConfig);
2418
2675
  this.wallet = this.createWalletNamespace(config.walletsConfig);
2676
+ this.protocols = new ProtocolsNamespace(this.protocol);
2677
+ }
2678
+ /**
2679
+ * Initializes the SDK
2680
+ * @param config SDK configuration (networks, wallets, protocol router settings)
2681
+ * @returns SDK instance
2682
+ */
2683
+ static async init(config) {
2684
+ let finalConfig;
2685
+ let isPremiumAvailable = false;
2686
+ if ("apiKey" in config && config.apiKey) {
2687
+ const apiClient = new ApiClient(config.apiKey);
2688
+ isPremiumAvailable = await apiClient.validate();
2689
+ if (isPremiumAvailable) {
2690
+ const apiResponse = await apiClient.sendRequest("config");
2691
+ if (!apiResponse.success) {
2692
+ throw new Error(apiResponse.error || "Failed to get onchain config");
2693
+ }
2694
+ const backendConfig = apiResponse.data;
2695
+ finalConfig = {
2696
+ integratorId: backendConfig.integratorId,
2697
+ walletsConfig: {
2698
+ embeddedWalletConfig: {
2699
+ provider: {
2700
+ type: "privy",
2701
+ providerConfig: {
2702
+ appId: backendConfig.privyAppId,
2703
+ appSecret: backendConfig.privyAppSecret
2704
+ }
2705
+ }
2706
+ },
2707
+ smartWalletConfig: {
2708
+ provider: {
2709
+ type: "default"
2710
+ }
2711
+ }
2712
+ },
2713
+ chain: {
2714
+ chainId: config.chainId || backendConfig.chainId,
2715
+ rpcUrl: backendConfig.rpcUrl,
2716
+ bundlerUrl: backendConfig.bundlerUrl
2717
+ },
2718
+ protocolsSecurityConfig: config.protocolsSecurityConfig,
2719
+ coinbaseCDPConfig: {
2720
+ apiKeyId: backendConfig.coinbaseCdpApiKey,
2721
+ apiKeySecret: backendConfig.coinbaseCdpApiKeySecret
2722
+ }
2723
+ };
2724
+ const sdk2 = new _MyceliumSDK(finalConfig, isPremiumAvailable, apiClient);
2725
+ sdk2.apiClient = apiClient;
2726
+ return sdk2;
2727
+ }
2728
+ }
2729
+ finalConfig = config;
2730
+ const sdk = new _MyceliumSDK(finalConfig, isPremiumAvailable);
2731
+ return sdk;
2419
2732
  }
2420
2733
  /**
2421
2734
  * Returns the chain manager instance for multi-chain operations
2422
2735
  * @public
2736
+ * @remarks
2737
+ * More about methods in {@link ChainManager}
2423
2738
  * @category Tools
2424
2739
  *
2425
2740
  * @returns ChainManager instance of the type {@link ChainManager}
@@ -2427,6 +2742,23 @@ var MyceliumSDK = class {
2427
2742
  get chainManager() {
2428
2743
  return this._chainManager;
2429
2744
  }
2745
+ /**
2746
+ * Returns a funding namespace to manage top ups & cash outs configurations
2747
+ * @public
2748
+ * @remarks
2749
+ * More about methods in {@link FundingNamespace}
2750
+ * @category Tools
2751
+ *
2752
+ * @returns Funding namespace of the type {@link FundingNamespace}
2753
+ */
2754
+ get funding() {
2755
+ if (!this.fundingNamespace) {
2756
+ throw new Error(
2757
+ "Ramp namespace is not initialized. Please, provide the configuration in the SDK initialization"
2758
+ );
2759
+ }
2760
+ return this.fundingNamespace;
2761
+ }
2430
2762
  /**
2431
2763
  * Recommends and initializes a protocol based on router settings
2432
2764
  *
@@ -2434,10 +2766,13 @@ var MyceliumSDK = class {
2434
2766
  * @param config Protocol router configuration (e.g. risk level)
2435
2767
  * @returns Selected protocol object of the type {@link Protocol}
2436
2768
  */
2437
- findProtocol(config) {
2438
- const protocolRouter = new ProtocolRouter(config, this.chainManager);
2439
- const protocol = protocolRouter.recommend();
2440
- protocol.instance.init(this.chainManager);
2769
+ selectProtocol(config, isPremiumAvailable, apiClient) {
2770
+ const protocolRouter = new ProtocolRouter(this.chainManager, isPremiumAvailable);
2771
+ const protocol = protocolRouter.select();
2772
+ if (!config) {
2773
+ throw new Error("Protocols security config is required");
2774
+ }
2775
+ protocol.init(this.chainManager, config, apiClient);
2441
2776
  return protocol;
2442
2777
  }
2443
2778
  /**
@@ -2495,6 +2830,7 @@ var MyceliumSDK = class {
2495
2830
  // Annotate the CommonJS export names for ESM import in node:
2496
2831
  0 && (module.exports = {
2497
2832
  DefaultSmartWallet,
2833
+ FundingNamespace,
2498
2834
  MyceliumSDK
2499
2835
  });
2500
2836
  //# sourceMappingURL=index.cjs.map