@unicitylabs/sphere-sdk 0.3.7 → 0.3.8

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.
@@ -41,7 +41,11 @@ var STORAGE_KEYS_GLOBAL = {
41
41
  /** Cached token registry JSON (fetched from remote) */
42
42
  TOKEN_REGISTRY_CACHE: "token_registry_cache",
43
43
  /** Timestamp of last token registry cache update (ms since epoch) */
44
- TOKEN_REGISTRY_CACHE_TS: "token_registry_cache_ts"
44
+ TOKEN_REGISTRY_CACHE_TS: "token_registry_cache_ts",
45
+ /** Cached price data JSON (from CoinGecko or other provider) */
46
+ PRICE_CACHE: "price_cache",
47
+ /** Timestamp of last price cache update (ms since epoch) */
48
+ PRICE_CACHE_TS: "price_cache_ts"
45
49
  };
46
50
  var STORAGE_KEYS_ADDRESS = {
47
51
  /** Pending transfers for this address */
@@ -166,7 +170,6 @@ var TIMEOUTS = {
166
170
  /** Sync interval */
167
171
  SYNC_INTERVAL: 6e4
168
172
  };
169
- var DEFAULT_MARKET_API_URL = "https://market-api.unicity.network";
170
173
 
171
174
  // impl/nodejs/storage/FileStorageProvider.ts
172
175
  var FileStorageProvider = class {
@@ -938,9 +941,7 @@ import {
938
941
  EventKinds,
939
942
  hashNametag,
940
943
  NostrClient,
941
- Filter,
942
- isChatMessage,
943
- isReadReceipt
944
+ Filter
944
945
  } from "@unicitylabs/nostr-js-sdk";
945
946
 
946
947
  // core/crypto.ts
@@ -1158,8 +1159,6 @@ var NostrTransportProvider = class {
1158
1159
  transferHandlers = /* @__PURE__ */ new Set();
1159
1160
  paymentRequestHandlers = /* @__PURE__ */ new Set();
1160
1161
  paymentRequestResponseHandlers = /* @__PURE__ */ new Set();
1161
- readReceiptHandlers = /* @__PURE__ */ new Set();
1162
- typingIndicatorHandlers = /* @__PURE__ */ new Set();
1163
1162
  broadcastHandlers = /* @__PURE__ */ new Map();
1164
1163
  eventCallbacks = /* @__PURE__ */ new Set();
1165
1164
  constructor(config) {
@@ -1411,18 +1410,6 @@ var NostrTransportProvider = class {
1411
1410
  const wrappedContent = senderNametag ? JSON.stringify({ senderNametag, text: content }) : content;
1412
1411
  const giftWrap = NIP17.createGiftWrap(this.keyManager, nostrRecipient, wrappedContent);
1413
1412
  await this.publishEvent(giftWrap);
1414
- const selfWrapContent = JSON.stringify({
1415
- selfWrap: true,
1416
- originalId: giftWrap.id,
1417
- recipientPubkey,
1418
- senderNametag,
1419
- text: content
1420
- });
1421
- const selfPubkey = this.keyManager.getPublicKeyHex();
1422
- const selfGiftWrap = NIP17.createGiftWrap(this.keyManager, selfPubkey, selfWrapContent);
1423
- this.publishEvent(selfGiftWrap).catch((err) => {
1424
- this.log("Self-wrap publish failed:", err);
1425
- });
1426
1413
  this.emitEvent({
1427
1414
  type: "message:sent",
1428
1415
  timestamp: Date.now(),
@@ -1521,37 +1508,6 @@ var NostrTransportProvider = class {
1521
1508
  this.paymentRequestResponseHandlers.add(handler);
1522
1509
  return () => this.paymentRequestResponseHandlers.delete(handler);
1523
1510
  }
1524
- // ===========================================================================
1525
- // Read Receipts
1526
- // ===========================================================================
1527
- async sendReadReceipt(recipientTransportPubkey, messageEventId) {
1528
- if (!this.keyManager) throw new Error("Not initialized");
1529
- const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
1530
- const event = NIP17.createReadReceipt(this.keyManager, nostrRecipient, messageEventId);
1531
- await this.publishEvent(event);
1532
- this.log("Sent read receipt for:", messageEventId, "to:", nostrRecipient.slice(0, 16));
1533
- }
1534
- onReadReceipt(handler) {
1535
- this.readReceiptHandlers.add(handler);
1536
- return () => this.readReceiptHandlers.delete(handler);
1537
- }
1538
- // ===========================================================================
1539
- // Typing Indicators
1540
- // ===========================================================================
1541
- async sendTypingIndicator(recipientTransportPubkey) {
1542
- if (!this.keyManager) throw new Error("Not initialized");
1543
- const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
1544
- const content = JSON.stringify({
1545
- type: "typing",
1546
- senderNametag: this.identity?.nametag
1547
- });
1548
- const event = NIP17.createGiftWrap(this.keyManager, nostrRecipient, content);
1549
- await this.publishEvent(event);
1550
- }
1551
- onTypingIndicator(handler) {
1552
- this.typingIndicatorHandlers.add(handler);
1553
- return () => this.typingIndicatorHandlers.delete(handler);
1554
- }
1555
1511
  /**
1556
1512
  * Resolve any identifier to full peer information.
1557
1513
  * Routes to the appropriate specific resolve method based on identifier format.
@@ -2005,74 +1961,11 @@ var NostrTransportProvider = class {
2005
1961
  const pm = NIP17.unwrap(event, this.keyManager);
2006
1962
  this.log("Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
2007
1963
  if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {
2008
- try {
2009
- const parsed = JSON.parse(pm.content);
2010
- if (parsed?.selfWrap && parsed.recipientPubkey) {
2011
- this.log("Self-wrap replay for recipient:", parsed.recipientPubkey?.slice(0, 16));
2012
- const message2 = {
2013
- id: parsed.originalId || pm.eventId,
2014
- senderTransportPubkey: pm.senderPubkey,
2015
- senderNametag: parsed.senderNametag,
2016
- recipientTransportPubkey: parsed.recipientPubkey,
2017
- content: parsed.text ?? "",
2018
- timestamp: pm.timestamp * 1e3,
2019
- encrypted: true,
2020
- isSelfWrap: true
2021
- };
2022
- for (const handler of this.messageHandlers) {
2023
- try {
2024
- handler(message2);
2025
- } catch (e) {
2026
- this.log("Self-wrap handler error:", e);
2027
- }
2028
- }
2029
- return;
2030
- }
2031
- } catch {
2032
- }
2033
- this.log("Skipping own non-self-wrap message");
2034
- return;
2035
- }
2036
- if (isReadReceipt(pm)) {
2037
- this.log("Read receipt from:", pm.senderPubkey?.slice(0, 16), "for:", pm.replyToEventId);
2038
- if (pm.replyToEventId) {
2039
- const receipt = {
2040
- senderTransportPubkey: pm.senderPubkey,
2041
- messageEventId: pm.replyToEventId,
2042
- timestamp: pm.timestamp * 1e3
2043
- };
2044
- for (const handler of this.readReceiptHandlers) {
2045
- try {
2046
- handler(receipt);
2047
- } catch (e) {
2048
- this.log("Read receipt handler error:", e);
2049
- }
2050
- }
2051
- }
1964
+ this.log("Skipping own message");
2052
1965
  return;
2053
1966
  }
2054
- try {
2055
- const parsed = JSON.parse(pm.content);
2056
- if (parsed?.type === "typing") {
2057
- this.log("Typing indicator from:", pm.senderPubkey?.slice(0, 16));
2058
- const indicator = {
2059
- senderTransportPubkey: pm.senderPubkey,
2060
- senderNametag: parsed.senderNametag,
2061
- timestamp: pm.timestamp * 1e3
2062
- };
2063
- for (const handler of this.typingIndicatorHandlers) {
2064
- try {
2065
- handler(indicator);
2066
- } catch (e) {
2067
- this.log("Typing handler error:", e);
2068
- }
2069
- }
2070
- return;
2071
- }
2072
- } catch {
2073
- }
2074
- if (!isChatMessage(pm)) {
2075
- this.log("Skipping unknown message kind:", pm.kind);
1967
+ if (pm.kind !== EventKinds.CHAT_MESSAGE) {
1968
+ this.log("Skipping non-chat message, kind:", pm.kind);
2076
1969
  return;
2077
1970
  }
2078
1971
  let content = pm.content;
@@ -2087,9 +1980,7 @@ var NostrTransportProvider = class {
2087
1980
  }
2088
1981
  this.log("DM received from:", senderNametag || pm.senderPubkey?.slice(0, 16), "content:", content?.slice(0, 50));
2089
1982
  const message = {
2090
- // Use outer gift wrap event.id so it matches the sender's stored giftWrap.id.
2091
- // This ensures read receipts reference an ID the sender recognizes.
2092
- id: event.id,
1983
+ id: pm.eventId,
2093
1984
  senderTransportPubkey: pm.senderPubkey,
2094
1985
  senderNametag,
2095
1986
  content,
@@ -3114,6 +3005,7 @@ async function loadIpnsModule() {
3114
3005
  async function createSignedRecord(keyPair, cid, sequenceNumber, lifetimeMs = DEFAULT_LIFETIME_MS) {
3115
3006
  const { createIPNSRecord, marshalIPNSRecord } = await loadIpnsModule();
3116
3007
  const record = await createIPNSRecord(
3008
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3117
3009
  keyPair,
3118
3010
  `/ipfs/${cid}`,
3119
3011
  sequenceNumber,
@@ -4855,26 +4747,37 @@ var CoinGeckoPriceProvider = class {
4855
4747
  timeout;
4856
4748
  debug;
4857
4749
  baseUrl;
4750
+ storage;
4751
+ /** In-flight fetch promise for deduplication of concurrent getPrices() calls */
4752
+ fetchPromise = null;
4753
+ /** Token names being fetched in the current in-flight request */
4754
+ fetchNames = null;
4755
+ /** Whether persistent cache has been loaded into memory */
4756
+ persistentCacheLoaded = false;
4757
+ /** Promise for loading persistent cache (deduplication) */
4758
+ loadCachePromise = null;
4858
4759
  constructor(config) {
4859
4760
  this.apiKey = config?.apiKey;
4860
4761
  this.cacheTtlMs = config?.cacheTtlMs ?? 6e4;
4861
4762
  this.timeout = config?.timeout ?? 1e4;
4862
4763
  this.debug = config?.debug ?? false;
4764
+ this.storage = config?.storage ?? null;
4863
4765
  this.baseUrl = config?.baseUrl ?? (this.apiKey ? "https://pro-api.coingecko.com/api/v3" : "https://api.coingecko.com/api/v3");
4864
4766
  }
4865
4767
  async getPrices(tokenNames) {
4866
4768
  if (tokenNames.length === 0) {
4867
4769
  return /* @__PURE__ */ new Map();
4868
4770
  }
4771
+ if (!this.persistentCacheLoaded && this.storage) {
4772
+ await this.loadFromStorage();
4773
+ }
4869
4774
  const now = Date.now();
4870
4775
  const result = /* @__PURE__ */ new Map();
4871
4776
  const uncachedNames = [];
4872
4777
  for (const name of tokenNames) {
4873
4778
  const cached = this.cache.get(name);
4874
4779
  if (cached && cached.expiresAt > now) {
4875
- if (cached.price !== null) {
4876
- result.set(name, cached.price);
4877
- }
4780
+ result.set(name, cached.price);
4878
4781
  } else {
4879
4782
  uncachedNames.push(name);
4880
4783
  }
@@ -4882,6 +4785,41 @@ var CoinGeckoPriceProvider = class {
4882
4785
  if (uncachedNames.length === 0) {
4883
4786
  return result;
4884
4787
  }
4788
+ if (this.fetchPromise && this.fetchNames) {
4789
+ const allCovered = uncachedNames.every((n) => this.fetchNames.has(n));
4790
+ if (allCovered) {
4791
+ if (this.debug) {
4792
+ console.log(`[CoinGecko] Deduplicating request, reusing in-flight fetch`);
4793
+ }
4794
+ const fetched = await this.fetchPromise;
4795
+ for (const name of uncachedNames) {
4796
+ const price = fetched.get(name);
4797
+ if (price) {
4798
+ result.set(name, price);
4799
+ }
4800
+ }
4801
+ return result;
4802
+ }
4803
+ }
4804
+ const fetchPromise = this.doFetch(uncachedNames);
4805
+ this.fetchPromise = fetchPromise;
4806
+ this.fetchNames = new Set(uncachedNames);
4807
+ try {
4808
+ const fetched = await fetchPromise;
4809
+ for (const [name, price] of fetched) {
4810
+ result.set(name, price);
4811
+ }
4812
+ } finally {
4813
+ if (this.fetchPromise === fetchPromise) {
4814
+ this.fetchPromise = null;
4815
+ this.fetchNames = null;
4816
+ }
4817
+ }
4818
+ return result;
4819
+ }
4820
+ async doFetch(uncachedNames) {
4821
+ const result = /* @__PURE__ */ new Map();
4822
+ const now = Date.now();
4885
4823
  try {
4886
4824
  const ids = uncachedNames.join(",");
4887
4825
  const url = `${this.baseUrl}/simple/price?ids=${encodeURIComponent(ids)}&vs_currencies=usd,eur&include_24hr_change=true`;
@@ -4897,6 +4835,9 @@ var CoinGeckoPriceProvider = class {
4897
4835
  signal: AbortSignal.timeout(this.timeout)
4898
4836
  });
4899
4837
  if (!response.ok) {
4838
+ if (response.status === 429) {
4839
+ this.extendCacheOnRateLimit(uncachedNames);
4840
+ }
4900
4841
  throw new Error(`CoinGecko API error: ${response.status} ${response.statusText}`);
4901
4842
  }
4902
4843
  const data = await response.json();
@@ -4915,25 +4856,113 @@ var CoinGeckoPriceProvider = class {
4915
4856
  }
4916
4857
  for (const name of uncachedNames) {
4917
4858
  if (!result.has(name)) {
4918
- this.cache.set(name, { price: null, expiresAt: now + this.cacheTtlMs });
4859
+ const zeroPrice = {
4860
+ tokenName: name,
4861
+ priceUsd: 0,
4862
+ priceEur: 0,
4863
+ change24h: 0,
4864
+ timestamp: now
4865
+ };
4866
+ this.cache.set(name, { price: zeroPrice, expiresAt: now + this.cacheTtlMs });
4867
+ result.set(name, zeroPrice);
4919
4868
  }
4920
4869
  }
4921
4870
  if (this.debug) {
4922
4871
  console.log(`[CoinGecko] Fetched ${result.size} prices`);
4923
4872
  }
4873
+ this.saveToStorage();
4924
4874
  } catch (error) {
4925
4875
  if (this.debug) {
4926
4876
  console.warn("[CoinGecko] Fetch failed, using stale cache:", error);
4927
4877
  }
4928
4878
  for (const name of uncachedNames) {
4929
4879
  const stale = this.cache.get(name);
4930
- if (stale?.price) {
4880
+ if (stale) {
4931
4881
  result.set(name, stale.price);
4932
4882
  }
4933
4883
  }
4934
4884
  }
4935
4885
  return result;
4936
4886
  }
4887
+ // ===========================================================================
4888
+ // Persistent Storage
4889
+ // ===========================================================================
4890
+ /**
4891
+ * Load cached prices from StorageProvider into in-memory cache.
4892
+ * Only loads entries that are still within cacheTtlMs.
4893
+ */
4894
+ async loadFromStorage() {
4895
+ if (this.loadCachePromise) {
4896
+ return this.loadCachePromise;
4897
+ }
4898
+ this.loadCachePromise = this.doLoadFromStorage();
4899
+ try {
4900
+ await this.loadCachePromise;
4901
+ } finally {
4902
+ this.loadCachePromise = null;
4903
+ }
4904
+ }
4905
+ async doLoadFromStorage() {
4906
+ this.persistentCacheLoaded = true;
4907
+ if (!this.storage) return;
4908
+ try {
4909
+ const [cached, cachedTs] = await Promise.all([
4910
+ this.storage.get(STORAGE_KEYS_GLOBAL.PRICE_CACHE),
4911
+ this.storage.get(STORAGE_KEYS_GLOBAL.PRICE_CACHE_TS)
4912
+ ]);
4913
+ if (!cached || !cachedTs) return;
4914
+ const ts = parseInt(cachedTs, 10);
4915
+ if (isNaN(ts)) return;
4916
+ const age = Date.now() - ts;
4917
+ if (age > this.cacheTtlMs) return;
4918
+ const data = JSON.parse(cached);
4919
+ const expiresAt = ts + this.cacheTtlMs;
4920
+ for (const [name, price] of Object.entries(data)) {
4921
+ if (!this.cache.has(name)) {
4922
+ this.cache.set(name, { price, expiresAt });
4923
+ }
4924
+ }
4925
+ if (this.debug) {
4926
+ console.log(`[CoinGecko] Loaded ${Object.keys(data).length} prices from persistent cache`);
4927
+ }
4928
+ } catch {
4929
+ }
4930
+ }
4931
+ /**
4932
+ * Save current prices to StorageProvider (fire-and-forget).
4933
+ */
4934
+ saveToStorage() {
4935
+ if (!this.storage) return;
4936
+ const data = {};
4937
+ for (const [name, entry] of this.cache) {
4938
+ data[name] = entry.price;
4939
+ }
4940
+ Promise.all([
4941
+ this.storage.set(STORAGE_KEYS_GLOBAL.PRICE_CACHE, JSON.stringify(data)),
4942
+ this.storage.set(STORAGE_KEYS_GLOBAL.PRICE_CACHE_TS, String(Date.now()))
4943
+ ]).catch(() => {
4944
+ });
4945
+ }
4946
+ // ===========================================================================
4947
+ // Rate-limit handling
4948
+ // ===========================================================================
4949
+ /**
4950
+ * On 429 rate-limit, extend stale cache entries so subsequent calls
4951
+ * don't immediately retry and hammer the API.
4952
+ */
4953
+ extendCacheOnRateLimit(names) {
4954
+ const backoffMs = 6e4;
4955
+ const extendedExpiry = Date.now() + backoffMs;
4956
+ for (const name of names) {
4957
+ const existing = this.cache.get(name);
4958
+ if (existing) {
4959
+ existing.expiresAt = Math.max(existing.expiresAt, extendedExpiry);
4960
+ }
4961
+ }
4962
+ if (this.debug) {
4963
+ console.warn(`[CoinGecko] Rate-limited (429), extended cache TTL by ${backoffMs / 1e3}s`);
4964
+ }
4965
+ }
4937
4966
  async getPrice(tokenName) {
4938
4967
  const prices = await this.getPrices([tokenName]);
4939
4968
  return prices.get(tokenName) ?? null;
@@ -4967,6 +4996,7 @@ var TokenRegistry = class _TokenRegistry {
4967
4996
  refreshTimer = null;
4968
4997
  lastRefreshAt = 0;
4969
4998
  refreshPromise = null;
4999
+ initialLoadPromise = null;
4970
5000
  constructor() {
4971
5001
  this.definitionsById = /* @__PURE__ */ new Map();
4972
5002
  this.definitionsBySymbol = /* @__PURE__ */ new Map();
@@ -5005,13 +5035,8 @@ var TokenRegistry = class _TokenRegistry {
5005
5035
  if (options.refreshIntervalMs !== void 0) {
5006
5036
  instance.refreshIntervalMs = options.refreshIntervalMs;
5007
5037
  }
5008
- if (instance.storage) {
5009
- instance.loadFromCache();
5010
- }
5011
5038
  const autoRefresh = options.autoRefresh ?? true;
5012
- if (autoRefresh && instance.remoteUrl) {
5013
- instance.startAutoRefresh();
5014
- }
5039
+ instance.initialLoadPromise = instance.performInitialLoad(autoRefresh);
5015
5040
  }
5016
5041
  /**
5017
5042
  * Reset the singleton instance (useful for testing).
@@ -5029,6 +5054,53 @@ var TokenRegistry = class _TokenRegistry {
5029
5054
  static destroy() {
5030
5055
  _TokenRegistry.resetInstance();
5031
5056
  }
5057
+ /**
5058
+ * Wait for the initial data load (cache or remote) to complete.
5059
+ * Returns true if data was loaded, false if not (timeout or no data source).
5060
+ *
5061
+ * @param timeoutMs - Maximum wait time in ms (default: 10s). Set to 0 for no timeout.
5062
+ */
5063
+ static async waitForReady(timeoutMs = 1e4) {
5064
+ const instance = _TokenRegistry.getInstance();
5065
+ if (!instance.initialLoadPromise) {
5066
+ return instance.definitionsById.size > 0;
5067
+ }
5068
+ if (timeoutMs <= 0) {
5069
+ return instance.initialLoadPromise;
5070
+ }
5071
+ return Promise.race([
5072
+ instance.initialLoadPromise,
5073
+ new Promise((resolve) => setTimeout(() => resolve(false), timeoutMs))
5074
+ ]);
5075
+ }
5076
+ // ===========================================================================
5077
+ // Initial Load
5078
+ // ===========================================================================
5079
+ /**
5080
+ * Perform initial data load: try cache first, fall back to remote fetch.
5081
+ * After initial data is available, start periodic auto-refresh if configured.
5082
+ */
5083
+ async performInitialLoad(autoRefresh) {
5084
+ let loaded = false;
5085
+ if (this.storage) {
5086
+ loaded = await this.loadFromCache();
5087
+ }
5088
+ if (loaded) {
5089
+ if (autoRefresh && this.remoteUrl) {
5090
+ this.startAutoRefresh();
5091
+ }
5092
+ return true;
5093
+ }
5094
+ if (autoRefresh && this.remoteUrl) {
5095
+ loaded = await this.refreshFromRemote();
5096
+ this.stopAutoRefresh();
5097
+ this.refreshTimer = setInterval(() => {
5098
+ this.refreshFromRemote();
5099
+ }, this.refreshIntervalMs);
5100
+ return loaded;
5101
+ }
5102
+ return false;
5103
+ }
5032
5104
  // ===========================================================================
5033
5105
  // Cache (StorageProvider)
5034
5106
  // ===========================================================================
@@ -5358,7 +5430,7 @@ function resolveL1Config(network, config) {
5358
5430
  enableVesting: config.enableVesting
5359
5431
  };
5360
5432
  }
5361
- function resolvePriceConfig(config) {
5433
+ function resolvePriceConfig(config, storage) {
5362
5434
  if (config === void 0) {
5363
5435
  return void 0;
5364
5436
  }
@@ -5368,7 +5440,8 @@ function resolvePriceConfig(config) {
5368
5440
  baseUrl: config.baseUrl,
5369
5441
  cacheTtlMs: config.cacheTtlMs,
5370
5442
  timeout: config.timeout,
5371
- debug: config.debug
5443
+ debug: config.debug,
5444
+ storage
5372
5445
  };
5373
5446
  }
5374
5447
  function resolveGroupChatConfig(network, config) {
@@ -5385,16 +5458,6 @@ function resolveGroupChatConfig(network, config) {
5385
5458
  relays: config.relays ?? [...netConfig.groupRelays]
5386
5459
  };
5387
5460
  }
5388
- function resolveMarketConfig(config) {
5389
- if (!config) return void 0;
5390
- if (config === true) {
5391
- return { apiUrl: DEFAULT_MARKET_API_URL };
5392
- }
5393
- return {
5394
- apiUrl: config.apiUrl ?? DEFAULT_MARKET_API_URL,
5395
- timeout: config.timeout
5396
- };
5397
- }
5398
5461
 
5399
5462
  // impl/nodejs/index.ts
5400
5463
  function createNodeProviders(config) {
@@ -5402,21 +5465,19 @@ function createNodeProviders(config) {
5402
5465
  const transportConfig = resolveTransportConfig(network, config?.transport);
5403
5466
  const oracleConfig = resolveOracleConfig(network, config?.oracle);
5404
5467
  const l1Config = resolveL1Config(network, config?.l1);
5405
- const priceConfig = resolvePriceConfig(config?.price);
5406
5468
  const storage = createFileStorageProvider({
5407
5469
  dataDir: config?.dataDir ?? "./sphere-data",
5408
5470
  ...config?.walletFileName ? { fileName: config.walletFileName } : {}
5409
5471
  });
5472
+ const priceConfig = resolvePriceConfig(config?.price, storage);
5410
5473
  const ipfsSync = config?.tokenSync?.ipfs;
5411
5474
  const ipfsTokenStorage = ipfsSync?.enabled ? createNodeIpfsStorageProvider(ipfsSync.config, storage) : void 0;
5412
5475
  const groupChat = resolveGroupChatConfig(network, config?.groupChat);
5413
5476
  const networkConfig = getNetworkConfig(network);
5414
5477
  TokenRegistry.configure({ remoteUrl: networkConfig.tokenRegistryUrl, storage });
5415
- const market = resolveMarketConfig(config?.market);
5416
5478
  return {
5417
5479
  storage,
5418
5480
  groupChat,
5419
- market,
5420
5481
  tokenStorage: createFileTokenStorageProvider({
5421
5482
  tokensDir: config?.tokensDir ?? "./sphere-tokens"
5422
5483
  }),