@unicitylabs/sphere-sdk 0.3.7 → 0.3.9
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/connect/index.cjs +770 -0
- package/dist/connect/index.cjs.map +1 -0
- package/dist/connect/index.d.cts +312 -0
- package/dist/connect/index.d.ts +312 -0
- package/dist/connect/index.js +747 -0
- package/dist/connect/index.js.map +1 -0
- package/dist/core/index.cjs +90 -2502
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +10 -165
- package/dist/core/index.d.ts +10 -165
- package/dist/core/index.js +86 -2498
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/connect/index.cjs +271 -0
- package/dist/impl/browser/connect/index.cjs.map +1 -0
- package/dist/impl/browser/connect/index.d.cts +137 -0
- package/dist/impl/browser/connect/index.d.ts +137 -0
- package/dist/impl/browser/connect/index.js +248 -0
- package/dist/impl/browser/connect/index.js.map +1 -0
- package/dist/impl/browser/index.cjs +201 -28
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +201 -28
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/browser/ipfs.cjs +6 -1
- package/dist/impl/browser/ipfs.cjs.map +1 -1
- package/dist/impl/browser/ipfs.js +6 -1
- package/dist/impl/browser/ipfs.js.map +1 -1
- package/dist/impl/nodejs/connect/index.cjs +372 -0
- package/dist/impl/nodejs/connect/index.cjs.map +1 -0
- package/dist/impl/nodejs/connect/index.d.cts +178 -0
- package/dist/impl/nodejs/connect/index.d.ts +178 -0
- package/dist/impl/nodejs/connect/index.js +333 -0
- package/dist/impl/nodejs/connect/index.js.map +1 -0
- package/dist/impl/nodejs/index.cjs +201 -28
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +2 -21
- package/dist/impl/nodejs/index.d.ts +2 -21
- package/dist/impl/nodejs/index.js +201 -28
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +232 -2513
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +59 -169
- package/dist/index.d.ts +59 -169
- package/dist/index.js +228 -2506
- package/dist/index.js.map +1 -1
- package/package.json +31 -1
|
@@ -90,7 +90,11 @@ var STORAGE_KEYS_GLOBAL = {
|
|
|
90
90
|
/** Cached token registry JSON (fetched from remote) */
|
|
91
91
|
TOKEN_REGISTRY_CACHE: "token_registry_cache",
|
|
92
92
|
/** Timestamp of last token registry cache update (ms since epoch) */
|
|
93
|
-
TOKEN_REGISTRY_CACHE_TS: "token_registry_cache_ts"
|
|
93
|
+
TOKEN_REGISTRY_CACHE_TS: "token_registry_cache_ts",
|
|
94
|
+
/** Cached price data JSON (from CoinGecko or other provider) */
|
|
95
|
+
PRICE_CACHE: "price_cache",
|
|
96
|
+
/** Timestamp of last price cache update (ms since epoch) */
|
|
97
|
+
PRICE_CACHE_TS: "price_cache_ts"
|
|
94
98
|
};
|
|
95
99
|
var STORAGE_KEYS_ADDRESS = {
|
|
96
100
|
/** Pending transfers for this address */
|
|
@@ -215,7 +219,6 @@ var TIMEOUTS = {
|
|
|
215
219
|
/** Sync interval */
|
|
216
220
|
SYNC_INTERVAL: 6e4
|
|
217
221
|
};
|
|
218
|
-
var DEFAULT_MARKET_API_URL = "https://market-api.unicity.network";
|
|
219
222
|
|
|
220
223
|
// impl/nodejs/storage/FileStorageProvider.ts
|
|
221
224
|
var FileStorageProvider = class {
|
|
@@ -3152,6 +3155,7 @@ async function loadIpnsModule() {
|
|
|
3152
3155
|
async function createSignedRecord(keyPair, cid, sequenceNumber, lifetimeMs = DEFAULT_LIFETIME_MS) {
|
|
3153
3156
|
const { createIPNSRecord, marshalIPNSRecord } = await loadIpnsModule();
|
|
3154
3157
|
const record = await createIPNSRecord(
|
|
3158
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3155
3159
|
keyPair,
|
|
3156
3160
|
`/ipfs/${cid}`,
|
|
3157
3161
|
sequenceNumber,
|
|
@@ -4893,26 +4897,37 @@ var CoinGeckoPriceProvider = class {
|
|
|
4893
4897
|
timeout;
|
|
4894
4898
|
debug;
|
|
4895
4899
|
baseUrl;
|
|
4900
|
+
storage;
|
|
4901
|
+
/** In-flight fetch promise for deduplication of concurrent getPrices() calls */
|
|
4902
|
+
fetchPromise = null;
|
|
4903
|
+
/** Token names being fetched in the current in-flight request */
|
|
4904
|
+
fetchNames = null;
|
|
4905
|
+
/** Whether persistent cache has been loaded into memory */
|
|
4906
|
+
persistentCacheLoaded = false;
|
|
4907
|
+
/** Promise for loading persistent cache (deduplication) */
|
|
4908
|
+
loadCachePromise = null;
|
|
4896
4909
|
constructor(config) {
|
|
4897
4910
|
this.apiKey = config?.apiKey;
|
|
4898
4911
|
this.cacheTtlMs = config?.cacheTtlMs ?? 6e4;
|
|
4899
4912
|
this.timeout = config?.timeout ?? 1e4;
|
|
4900
4913
|
this.debug = config?.debug ?? false;
|
|
4914
|
+
this.storage = config?.storage ?? null;
|
|
4901
4915
|
this.baseUrl = config?.baseUrl ?? (this.apiKey ? "https://pro-api.coingecko.com/api/v3" : "https://api.coingecko.com/api/v3");
|
|
4902
4916
|
}
|
|
4903
4917
|
async getPrices(tokenNames) {
|
|
4904
4918
|
if (tokenNames.length === 0) {
|
|
4905
4919
|
return /* @__PURE__ */ new Map();
|
|
4906
4920
|
}
|
|
4921
|
+
if (!this.persistentCacheLoaded && this.storage) {
|
|
4922
|
+
await this.loadFromStorage();
|
|
4923
|
+
}
|
|
4907
4924
|
const now = Date.now();
|
|
4908
4925
|
const result = /* @__PURE__ */ new Map();
|
|
4909
4926
|
const uncachedNames = [];
|
|
4910
4927
|
for (const name of tokenNames) {
|
|
4911
4928
|
const cached = this.cache.get(name);
|
|
4912
4929
|
if (cached && cached.expiresAt > now) {
|
|
4913
|
-
|
|
4914
|
-
result.set(name, cached.price);
|
|
4915
|
-
}
|
|
4930
|
+
result.set(name, cached.price);
|
|
4916
4931
|
} else {
|
|
4917
4932
|
uncachedNames.push(name);
|
|
4918
4933
|
}
|
|
@@ -4920,6 +4935,41 @@ var CoinGeckoPriceProvider = class {
|
|
|
4920
4935
|
if (uncachedNames.length === 0) {
|
|
4921
4936
|
return result;
|
|
4922
4937
|
}
|
|
4938
|
+
if (this.fetchPromise && this.fetchNames) {
|
|
4939
|
+
const allCovered = uncachedNames.every((n) => this.fetchNames.has(n));
|
|
4940
|
+
if (allCovered) {
|
|
4941
|
+
if (this.debug) {
|
|
4942
|
+
console.log(`[CoinGecko] Deduplicating request, reusing in-flight fetch`);
|
|
4943
|
+
}
|
|
4944
|
+
const fetched = await this.fetchPromise;
|
|
4945
|
+
for (const name of uncachedNames) {
|
|
4946
|
+
const price = fetched.get(name);
|
|
4947
|
+
if (price) {
|
|
4948
|
+
result.set(name, price);
|
|
4949
|
+
}
|
|
4950
|
+
}
|
|
4951
|
+
return result;
|
|
4952
|
+
}
|
|
4953
|
+
}
|
|
4954
|
+
const fetchPromise = this.doFetch(uncachedNames);
|
|
4955
|
+
this.fetchPromise = fetchPromise;
|
|
4956
|
+
this.fetchNames = new Set(uncachedNames);
|
|
4957
|
+
try {
|
|
4958
|
+
const fetched = await fetchPromise;
|
|
4959
|
+
for (const [name, price] of fetched) {
|
|
4960
|
+
result.set(name, price);
|
|
4961
|
+
}
|
|
4962
|
+
} finally {
|
|
4963
|
+
if (this.fetchPromise === fetchPromise) {
|
|
4964
|
+
this.fetchPromise = null;
|
|
4965
|
+
this.fetchNames = null;
|
|
4966
|
+
}
|
|
4967
|
+
}
|
|
4968
|
+
return result;
|
|
4969
|
+
}
|
|
4970
|
+
async doFetch(uncachedNames) {
|
|
4971
|
+
const result = /* @__PURE__ */ new Map();
|
|
4972
|
+
const now = Date.now();
|
|
4923
4973
|
try {
|
|
4924
4974
|
const ids = uncachedNames.join(",");
|
|
4925
4975
|
const url = `${this.baseUrl}/simple/price?ids=${encodeURIComponent(ids)}&vs_currencies=usd,eur&include_24hr_change=true`;
|
|
@@ -4935,6 +4985,9 @@ var CoinGeckoPriceProvider = class {
|
|
|
4935
4985
|
signal: AbortSignal.timeout(this.timeout)
|
|
4936
4986
|
});
|
|
4937
4987
|
if (!response.ok) {
|
|
4988
|
+
if (response.status === 429) {
|
|
4989
|
+
this.extendCacheOnRateLimit(uncachedNames);
|
|
4990
|
+
}
|
|
4938
4991
|
throw new Error(`CoinGecko API error: ${response.status} ${response.statusText}`);
|
|
4939
4992
|
}
|
|
4940
4993
|
const data = await response.json();
|
|
@@ -4953,25 +5006,113 @@ var CoinGeckoPriceProvider = class {
|
|
|
4953
5006
|
}
|
|
4954
5007
|
for (const name of uncachedNames) {
|
|
4955
5008
|
if (!result.has(name)) {
|
|
4956
|
-
|
|
5009
|
+
const zeroPrice = {
|
|
5010
|
+
tokenName: name,
|
|
5011
|
+
priceUsd: 0,
|
|
5012
|
+
priceEur: 0,
|
|
5013
|
+
change24h: 0,
|
|
5014
|
+
timestamp: now
|
|
5015
|
+
};
|
|
5016
|
+
this.cache.set(name, { price: zeroPrice, expiresAt: now + this.cacheTtlMs });
|
|
5017
|
+
result.set(name, zeroPrice);
|
|
4957
5018
|
}
|
|
4958
5019
|
}
|
|
4959
5020
|
if (this.debug) {
|
|
4960
5021
|
console.log(`[CoinGecko] Fetched ${result.size} prices`);
|
|
4961
5022
|
}
|
|
5023
|
+
this.saveToStorage();
|
|
4962
5024
|
} catch (error) {
|
|
4963
5025
|
if (this.debug) {
|
|
4964
5026
|
console.warn("[CoinGecko] Fetch failed, using stale cache:", error);
|
|
4965
5027
|
}
|
|
4966
5028
|
for (const name of uncachedNames) {
|
|
4967
5029
|
const stale = this.cache.get(name);
|
|
4968
|
-
if (stale
|
|
5030
|
+
if (stale) {
|
|
4969
5031
|
result.set(name, stale.price);
|
|
4970
5032
|
}
|
|
4971
5033
|
}
|
|
4972
5034
|
}
|
|
4973
5035
|
return result;
|
|
4974
5036
|
}
|
|
5037
|
+
// ===========================================================================
|
|
5038
|
+
// Persistent Storage
|
|
5039
|
+
// ===========================================================================
|
|
5040
|
+
/**
|
|
5041
|
+
* Load cached prices from StorageProvider into in-memory cache.
|
|
5042
|
+
* Only loads entries that are still within cacheTtlMs.
|
|
5043
|
+
*/
|
|
5044
|
+
async loadFromStorage() {
|
|
5045
|
+
if (this.loadCachePromise) {
|
|
5046
|
+
return this.loadCachePromise;
|
|
5047
|
+
}
|
|
5048
|
+
this.loadCachePromise = this.doLoadFromStorage();
|
|
5049
|
+
try {
|
|
5050
|
+
await this.loadCachePromise;
|
|
5051
|
+
} finally {
|
|
5052
|
+
this.loadCachePromise = null;
|
|
5053
|
+
}
|
|
5054
|
+
}
|
|
5055
|
+
async doLoadFromStorage() {
|
|
5056
|
+
this.persistentCacheLoaded = true;
|
|
5057
|
+
if (!this.storage) return;
|
|
5058
|
+
try {
|
|
5059
|
+
const [cached, cachedTs] = await Promise.all([
|
|
5060
|
+
this.storage.get(STORAGE_KEYS_GLOBAL.PRICE_CACHE),
|
|
5061
|
+
this.storage.get(STORAGE_KEYS_GLOBAL.PRICE_CACHE_TS)
|
|
5062
|
+
]);
|
|
5063
|
+
if (!cached || !cachedTs) return;
|
|
5064
|
+
const ts = parseInt(cachedTs, 10);
|
|
5065
|
+
if (isNaN(ts)) return;
|
|
5066
|
+
const age = Date.now() - ts;
|
|
5067
|
+
if (age > this.cacheTtlMs) return;
|
|
5068
|
+
const data = JSON.parse(cached);
|
|
5069
|
+
const expiresAt = ts + this.cacheTtlMs;
|
|
5070
|
+
for (const [name, price] of Object.entries(data)) {
|
|
5071
|
+
if (!this.cache.has(name)) {
|
|
5072
|
+
this.cache.set(name, { price, expiresAt });
|
|
5073
|
+
}
|
|
5074
|
+
}
|
|
5075
|
+
if (this.debug) {
|
|
5076
|
+
console.log(`[CoinGecko] Loaded ${Object.keys(data).length} prices from persistent cache`);
|
|
5077
|
+
}
|
|
5078
|
+
} catch {
|
|
5079
|
+
}
|
|
5080
|
+
}
|
|
5081
|
+
/**
|
|
5082
|
+
* Save current prices to StorageProvider (fire-and-forget).
|
|
5083
|
+
*/
|
|
5084
|
+
saveToStorage() {
|
|
5085
|
+
if (!this.storage) return;
|
|
5086
|
+
const data = {};
|
|
5087
|
+
for (const [name, entry] of this.cache) {
|
|
5088
|
+
data[name] = entry.price;
|
|
5089
|
+
}
|
|
5090
|
+
Promise.all([
|
|
5091
|
+
this.storage.set(STORAGE_KEYS_GLOBAL.PRICE_CACHE, JSON.stringify(data)),
|
|
5092
|
+
this.storage.set(STORAGE_KEYS_GLOBAL.PRICE_CACHE_TS, String(Date.now()))
|
|
5093
|
+
]).catch(() => {
|
|
5094
|
+
});
|
|
5095
|
+
}
|
|
5096
|
+
// ===========================================================================
|
|
5097
|
+
// Rate-limit handling
|
|
5098
|
+
// ===========================================================================
|
|
5099
|
+
/**
|
|
5100
|
+
* On 429 rate-limit, extend stale cache entries so subsequent calls
|
|
5101
|
+
* don't immediately retry and hammer the API.
|
|
5102
|
+
*/
|
|
5103
|
+
extendCacheOnRateLimit(names) {
|
|
5104
|
+
const backoffMs = 6e4;
|
|
5105
|
+
const extendedExpiry = Date.now() + backoffMs;
|
|
5106
|
+
for (const name of names) {
|
|
5107
|
+
const existing = this.cache.get(name);
|
|
5108
|
+
if (existing) {
|
|
5109
|
+
existing.expiresAt = Math.max(existing.expiresAt, extendedExpiry);
|
|
5110
|
+
}
|
|
5111
|
+
}
|
|
5112
|
+
if (this.debug) {
|
|
5113
|
+
console.warn(`[CoinGecko] Rate-limited (429), extended cache TTL by ${backoffMs / 1e3}s`);
|
|
5114
|
+
}
|
|
5115
|
+
}
|
|
4975
5116
|
async getPrice(tokenName) {
|
|
4976
5117
|
const prices = await this.getPrices([tokenName]);
|
|
4977
5118
|
return prices.get(tokenName) ?? null;
|
|
@@ -5005,6 +5146,7 @@ var TokenRegistry = class _TokenRegistry {
|
|
|
5005
5146
|
refreshTimer = null;
|
|
5006
5147
|
lastRefreshAt = 0;
|
|
5007
5148
|
refreshPromise = null;
|
|
5149
|
+
initialLoadPromise = null;
|
|
5008
5150
|
constructor() {
|
|
5009
5151
|
this.definitionsById = /* @__PURE__ */ new Map();
|
|
5010
5152
|
this.definitionsBySymbol = /* @__PURE__ */ new Map();
|
|
@@ -5043,13 +5185,8 @@ var TokenRegistry = class _TokenRegistry {
|
|
|
5043
5185
|
if (options.refreshIntervalMs !== void 0) {
|
|
5044
5186
|
instance.refreshIntervalMs = options.refreshIntervalMs;
|
|
5045
5187
|
}
|
|
5046
|
-
if (instance.storage) {
|
|
5047
|
-
instance.loadFromCache();
|
|
5048
|
-
}
|
|
5049
5188
|
const autoRefresh = options.autoRefresh ?? true;
|
|
5050
|
-
|
|
5051
|
-
instance.startAutoRefresh();
|
|
5052
|
-
}
|
|
5189
|
+
instance.initialLoadPromise = instance.performInitialLoad(autoRefresh);
|
|
5053
5190
|
}
|
|
5054
5191
|
/**
|
|
5055
5192
|
* Reset the singleton instance (useful for testing).
|
|
@@ -5067,6 +5204,53 @@ var TokenRegistry = class _TokenRegistry {
|
|
|
5067
5204
|
static destroy() {
|
|
5068
5205
|
_TokenRegistry.resetInstance();
|
|
5069
5206
|
}
|
|
5207
|
+
/**
|
|
5208
|
+
* Wait for the initial data load (cache or remote) to complete.
|
|
5209
|
+
* Returns true if data was loaded, false if not (timeout or no data source).
|
|
5210
|
+
*
|
|
5211
|
+
* @param timeoutMs - Maximum wait time in ms (default: 10s). Set to 0 for no timeout.
|
|
5212
|
+
*/
|
|
5213
|
+
static async waitForReady(timeoutMs = 1e4) {
|
|
5214
|
+
const instance = _TokenRegistry.getInstance();
|
|
5215
|
+
if (!instance.initialLoadPromise) {
|
|
5216
|
+
return instance.definitionsById.size > 0;
|
|
5217
|
+
}
|
|
5218
|
+
if (timeoutMs <= 0) {
|
|
5219
|
+
return instance.initialLoadPromise;
|
|
5220
|
+
}
|
|
5221
|
+
return Promise.race([
|
|
5222
|
+
instance.initialLoadPromise,
|
|
5223
|
+
new Promise((resolve) => setTimeout(() => resolve(false), timeoutMs))
|
|
5224
|
+
]);
|
|
5225
|
+
}
|
|
5226
|
+
// ===========================================================================
|
|
5227
|
+
// Initial Load
|
|
5228
|
+
// ===========================================================================
|
|
5229
|
+
/**
|
|
5230
|
+
* Perform initial data load: try cache first, fall back to remote fetch.
|
|
5231
|
+
* After initial data is available, start periodic auto-refresh if configured.
|
|
5232
|
+
*/
|
|
5233
|
+
async performInitialLoad(autoRefresh) {
|
|
5234
|
+
let loaded = false;
|
|
5235
|
+
if (this.storage) {
|
|
5236
|
+
loaded = await this.loadFromCache();
|
|
5237
|
+
}
|
|
5238
|
+
if (loaded) {
|
|
5239
|
+
if (autoRefresh && this.remoteUrl) {
|
|
5240
|
+
this.startAutoRefresh();
|
|
5241
|
+
}
|
|
5242
|
+
return true;
|
|
5243
|
+
}
|
|
5244
|
+
if (autoRefresh && this.remoteUrl) {
|
|
5245
|
+
loaded = await this.refreshFromRemote();
|
|
5246
|
+
this.stopAutoRefresh();
|
|
5247
|
+
this.refreshTimer = setInterval(() => {
|
|
5248
|
+
this.refreshFromRemote();
|
|
5249
|
+
}, this.refreshIntervalMs);
|
|
5250
|
+
return loaded;
|
|
5251
|
+
}
|
|
5252
|
+
return false;
|
|
5253
|
+
}
|
|
5070
5254
|
// ===========================================================================
|
|
5071
5255
|
// Cache (StorageProvider)
|
|
5072
5256
|
// ===========================================================================
|
|
@@ -5396,7 +5580,7 @@ function resolveL1Config(network, config) {
|
|
|
5396
5580
|
enableVesting: config.enableVesting
|
|
5397
5581
|
};
|
|
5398
5582
|
}
|
|
5399
|
-
function resolvePriceConfig(config) {
|
|
5583
|
+
function resolvePriceConfig(config, storage) {
|
|
5400
5584
|
if (config === void 0) {
|
|
5401
5585
|
return void 0;
|
|
5402
5586
|
}
|
|
@@ -5406,7 +5590,8 @@ function resolvePriceConfig(config) {
|
|
|
5406
5590
|
baseUrl: config.baseUrl,
|
|
5407
5591
|
cacheTtlMs: config.cacheTtlMs,
|
|
5408
5592
|
timeout: config.timeout,
|
|
5409
|
-
debug: config.debug
|
|
5593
|
+
debug: config.debug,
|
|
5594
|
+
storage
|
|
5410
5595
|
};
|
|
5411
5596
|
}
|
|
5412
5597
|
function resolveGroupChatConfig(network, config) {
|
|
@@ -5423,16 +5608,6 @@ function resolveGroupChatConfig(network, config) {
|
|
|
5423
5608
|
relays: config.relays ?? [...netConfig.groupRelays]
|
|
5424
5609
|
};
|
|
5425
5610
|
}
|
|
5426
|
-
function resolveMarketConfig(config) {
|
|
5427
|
-
if (!config) return void 0;
|
|
5428
|
-
if (config === true) {
|
|
5429
|
-
return { apiUrl: DEFAULT_MARKET_API_URL };
|
|
5430
|
-
}
|
|
5431
|
-
return {
|
|
5432
|
-
apiUrl: config.apiUrl ?? DEFAULT_MARKET_API_URL,
|
|
5433
|
-
timeout: config.timeout
|
|
5434
|
-
};
|
|
5435
|
-
}
|
|
5436
5611
|
|
|
5437
5612
|
// impl/nodejs/index.ts
|
|
5438
5613
|
function createNodeProviders(config) {
|
|
@@ -5440,21 +5615,19 @@ function createNodeProviders(config) {
|
|
|
5440
5615
|
const transportConfig = resolveTransportConfig(network, config?.transport);
|
|
5441
5616
|
const oracleConfig = resolveOracleConfig(network, config?.oracle);
|
|
5442
5617
|
const l1Config = resolveL1Config(network, config?.l1);
|
|
5443
|
-
const priceConfig = resolvePriceConfig(config?.price);
|
|
5444
5618
|
const storage = createFileStorageProvider({
|
|
5445
5619
|
dataDir: config?.dataDir ?? "./sphere-data",
|
|
5446
5620
|
...config?.walletFileName ? { fileName: config.walletFileName } : {}
|
|
5447
5621
|
});
|
|
5622
|
+
const priceConfig = resolvePriceConfig(config?.price, storage);
|
|
5448
5623
|
const ipfsSync = config?.tokenSync?.ipfs;
|
|
5449
5624
|
const ipfsTokenStorage = ipfsSync?.enabled ? createNodeIpfsStorageProvider(ipfsSync.config, storage) : void 0;
|
|
5450
5625
|
const groupChat = resolveGroupChatConfig(network, config?.groupChat);
|
|
5451
5626
|
const networkConfig = getNetworkConfig(network);
|
|
5452
5627
|
TokenRegistry.configure({ remoteUrl: networkConfig.tokenRegistryUrl, storage });
|
|
5453
|
-
const market = resolveMarketConfig(config?.market);
|
|
5454
5628
|
return {
|
|
5455
5629
|
storage,
|
|
5456
5630
|
groupChat,
|
|
5457
|
-
market,
|
|
5458
5631
|
tokenStorage: createFileTokenStorageProvider({
|
|
5459
5632
|
tokensDir: config?.tokensDir ?? "./sphere-tokens"
|
|
5460
5633
|
}),
|