@fileverse-dev/formulajs 4.4.11-mod-76 → 4.4.11-mod-77

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/lib/cjs/index.cjs CHANGED
@@ -13132,7 +13132,6 @@ const UTILITY = {
13132
13132
  };
13133
13133
  const MAX_PAGE_LIMIT = 250;
13134
13134
 
13135
- // if data block need API key
13136
13135
  const SERVICES_API_KEY = {
13137
13136
  Etherscan: 'Etherscan',
13138
13137
  Coingecko: 'Coingecko',
@@ -13145,6 +13144,27 @@ const SERVICES_API_KEY = {
13145
13144
  Defillama: 'Defillama'
13146
13145
  };
13147
13146
 
13147
+ const fromTimeStampToBlock = async (timestamp, chain, apiKey) => {
13148
+ if(!timestamp || !chain || !apiKey) return
13149
+ const chainId = CHAIN_ID_MAP[chain];
13150
+ const url = `https://api.etherscan.io/v2/api?module=block&action=getblocknobytime&timestamp=${timestamp}&closest=before&apikey=${apiKey}&chainId=${chainId}`;
13151
+ const res = await fetch(url);
13152
+ const json = await res.json();
13153
+ return parseInt(json.result);
13154
+
13155
+ };
13156
+
13157
+ var fromTimestampToBlock = {
13158
+ fromTimeStampToBlock
13159
+ };
13160
+
13161
+ function toTimestamp(dateStr) {
13162
+ // Expecting format: "DD/MM/YYYY"
13163
+ const [day, month, year] = dateStr.split("/").map(Number);
13164
+ const date = new Date(year, month - 1, day);
13165
+ return Math.floor(date.getTime() / 1000); // Unix timestamp in seconds
13166
+ }
13167
+
13148
13168
  class ValidationError extends Error {
13149
13169
  constructor(message) {
13150
13170
  super(message);
@@ -13189,139 +13209,6 @@ class InvalidApiKeyError extends Error {
13189
13209
  }
13190
13210
  }
13191
13211
 
13192
- const stagingFileverseProxyUrl = "https://staging-api-proxy-ca4268d7d581.herokuapp.com/proxy";
13193
- const productionFileverseProxyUrl = `${process.env.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`;
13194
- // Proxy map configuration
13195
- const PROXY_MAP = {
13196
- Etherscan: {
13197
- url: productionFileverseProxyUrl || stagingFileverseProxyUrl,
13198
- removeParams: ['apikey']
13199
- },
13200
- Basescan: {
13201
- url: productionFileverseProxyUrl || stagingFileverseProxyUrl,
13202
- removeParams: ['apikey']
13203
- },
13204
- Gnosisscan: {
13205
- url: productionFileverseProxyUrl || stagingFileverseProxyUrl,
13206
- removeParams: ['apikey']
13207
- },
13208
- Coingecko: {
13209
- url: productionFileverseProxyUrl || stagingFileverseProxyUrl,
13210
- removeParams: ['apikey']
13211
- },
13212
- Firefly: {
13213
- url: productionFileverseProxyUrl || stagingFileverseProxyUrl,
13214
- removeParams: ['apikey']
13215
- },
13216
- Neynar: {
13217
- url: productionFileverseProxyUrl || stagingFileverseProxyUrl,
13218
- removeParams: ['api_key']
13219
- },
13220
- Safe: {
13221
- url: productionFileverseProxyUrl || stagingFileverseProxyUrl,
13222
- removeParams: ['api_key']
13223
- },
13224
- Defillama: {
13225
- url: productionFileverseProxyUrl || stagingFileverseProxyUrl,
13226
- removeParams: ['api_key']
13227
- },
13228
- GnosisPay: {
13229
- url: productionFileverseProxyUrl || stagingFileverseProxyUrl,
13230
- removeParams: ['api_key']
13231
- },
13232
- // Add more services as needed. It can be direct url instead of ENV variable
13233
- // ANOTHER_SERVICE: "https://another-proxy-url.com"
13234
- };
13235
-
13236
- /**
13237
- * Removes specified parameters from a URL
13238
- * @param {string} url - The original URL
13239
- * @param {string[]} paramsToRemove - Array of parameter names to remove
13240
- * @returns {string} URL with specified parameters removed
13241
- */
13242
- function removeUrlParams(url, paramsToRemove) {
13243
- if (!paramsToRemove || paramsToRemove.length === 0) {
13244
- return url;
13245
- }
13246
-
13247
- const urlObj = new URL(url);
13248
-
13249
- paramsToRemove.forEach(param => {
13250
- if (urlObj.searchParams.has(param)) {
13251
- urlObj.searchParams.delete(param);
13252
- }
13253
- });
13254
-
13255
- return urlObj.toString();
13256
- }
13257
-
13258
- /**
13259
- * Handles URL routing through proxy or direct API calls
13260
- * @param {string} url - The original API URL
13261
- * @param {string} serviceName - [OPTIONAL] The name of the service (e.g., 'EOA')
13262
- * @param {object} headers - [OPTIONAL] The name of the service (e.g., 'EOA')
13263
- * @returns {Object} Object containing URL and HEADERS for the fetch request
13264
- */
13265
- function getUrlAndHeaders({ url, serviceName, headers = {} }) {
13266
- // Check if proxy is enabled in localStorage
13267
- const apiKeyLS = window.localStorage.getItem(SERVICES_API_KEY[serviceName]);
13268
- const isProxyModeEnabledValue = apiKeyLS === 'DEFAULT_PROXY_MODE';
13269
-
13270
- // Check if proxy URL exists for this service
13271
- const proxyConfig = PROXY_MAP[serviceName];
13272
-
13273
- if (!proxyConfig && SERVICES_API_KEY[serviceName] && (!apiKeyLS || apiKeyLS === '')) {
13274
- throw new MissingApiKeyError(SERVICES_API_KEY[serviceName])
13275
- }
13276
-
13277
- // If proxy mode is enabled AND proxy URL exists for this service
13278
- if ((isProxyModeEnabledValue || !apiKeyLS || apiKeyLS === '') && proxyConfig) {
13279
- // Remove specified parameters from the target URL
13280
- const cleanedUrl = removeUrlParams(url, proxyConfig.removeParams);
13281
-
13282
- return {
13283
- URL: proxyConfig.url,
13284
- HEADERS: {
13285
- 'target-url': cleanedUrl,
13286
- method: 'GET',
13287
- 'Content-Type': 'application/json'
13288
- }
13289
- };
13290
- }
13291
-
13292
- return {
13293
- URL: url,
13294
- HEADERS: {
13295
- ...headers,
13296
- }
13297
- };
13298
- }
13299
-
13300
- const fromTimeStampToBlock = async (timestamp, chain, apiKey) => {
13301
- if (!timestamp || !chain) return
13302
- const chainId = CHAIN_ID_MAP[chain];
13303
- const url = `https://api.etherscan.io/v2/api?module=block&action=getblocknobytime&timestamp=${timestamp}&closest=before&apikey=${apiKey}&chainId=${chainId}`;
13304
- const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url, serviceName: 'Etherscan', headers: {} });
13305
- const res = await fetch(finalUrl, {
13306
- method: 'GET',
13307
- headers: HEADERS,
13308
- });
13309
- const json = await res.json();
13310
- return parseInt(json.result);
13311
-
13312
- };
13313
-
13314
- var fromTimestampToBlock = {
13315
- fromTimeStampToBlock
13316
- };
13317
-
13318
- function toTimestamp(dateStr) {
13319
- // Expecting format: "DD/MM/YYYY"
13320
- const [day, month, year] = dateStr.split("/").map(Number);
13321
- const date = new Date(year, month - 1, day);
13322
- return Math.floor(date.getTime() / 1000); // Unix timestamp in seconds
13323
- }
13324
-
13325
13212
  const isAddress = (input) => {
13326
13213
  return (/^0x[a-fA-F0-9]{40}$/.test(input))
13327
13214
  };
@@ -13362,9 +13249,16 @@ async function fromEnsNameToAddress(name) {
13362
13249
  return null
13363
13250
  }
13364
13251
  }
13252
+ const validateAndGetAddress = async (address) => {
13253
+ if(isAddress$1.isAddress(address)) return address
13254
+
13255
+ const resolvedAddress = await fromEnsNameToAddress(address);
13256
+ if(resolvedAddress) return resolvedAddress
13257
+ throw new ValidationError("Invalid address")
13258
+ };
13365
13259
 
13366
13260
  var fromEnsNameToAddress$1 = {
13367
- fromEnsNameToAddress
13261
+ validateAndGetAddress
13368
13262
  };
13369
13263
 
13370
13264
  async function handleScanRequest({
@@ -13385,12 +13279,8 @@ async function handleScanRequest({
13385
13279
  GNOSIS: { url: 'https://api.gnosisscan.io/api', apiKeyName: SERVICES_API_KEY.Gnosisscan }
13386
13280
  };
13387
13281
 
13388
- if (!isAddress$1.isAddress(address) && type !== 'gas') {
13389
- const ensName = address;
13390
- address = await fromEnsNameToAddress$1.fromEnsNameToAddress(address);
13391
- if (!address) {
13392
- throw new EnsError(ensName)
13393
- }
13282
+ if (type !== 'gas') {
13283
+ address = await fromEnsNameToAddress$1.validateAndGetAddress(address);
13394
13284
  }
13395
13285
 
13396
13286
  const apiInfo = API_INFO_MAP[functionName];
@@ -13423,11 +13313,7 @@ async function handleScanRequest({
13423
13313
  }
13424
13314
  url += `&page=${page}&offset=${offset}`;
13425
13315
  }
13426
- const { URL: finalUrl, HEADERS } = getUrlAndHeaders({url, serviceName: apiInfo.apiKeyName, headers: {}});
13427
- const res = await fetch(finalUrl, {
13428
- method: 'GET',
13429
- headers: HEADERS,
13430
- });
13316
+ const res = await fetch(url);
13431
13317
  if (!res.ok) {
13432
13318
  throw new NetworkError(apiInfo.apiKeyName, res.status)
13433
13319
  }
@@ -13446,19 +13332,14 @@ async function handleScanRequest({
13446
13332
  }
13447
13333
 
13448
13334
  const fromUsernameToFid = async (username, apiKey) => {
13449
- if (!username) return null
13335
+ if(!username) return null
13450
13336
  const url = `https://api.neynar.com/v2/farcaster/user/search/?q=${username}&limit=5`;
13451
- const { URL: finalUrl, HEADERS } = getUrlAndHeaders({
13452
- url, serviceName: 'Neynar', headers: {
13337
+ const res = await fetch(url, {
13338
+ headers: {
13453
13339
  'x-api-key': apiKey,
13454
13340
  'x-neynar-experimental': 'false'
13455
13341
  }
13456
13342
  });
13457
-
13458
- const res = await fetch(finalUrl, {
13459
- method: 'GET',
13460
- headers: HEADERS,
13461
- });
13462
13343
  const json = await res.json();
13463
13344
  const users = json.result ? json.result.users : [];
13464
13345
  const user = users.find(user => user.username === username);
@@ -17698,9 +17579,9 @@ const aaveParamsSchema = objectType({
17698
17579
 
17699
17580
  async function FIREFLY() {
17700
17581
  try {
17701
- const [platform, contentType, identifier, start = 0, end = 10] = argsToArray(arguments);
17582
+ const [platform, contentType, identifier, start = 0, end = 10] = argsToArray(arguments);
17702
17583
 
17703
- validateParams(fireflyParamsSchema, {
17584
+ validateParams(fireflyParamsSchema, {
17704
17585
  platform,
17705
17586
  contentType,
17706
17587
  identifier,
@@ -17709,6 +17590,9 @@ async function FIREFLY() {
17709
17590
  });
17710
17591
 
17711
17592
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Firefly);
17593
+ if (!apiKey) {
17594
+ throw new MissingApiKeyError(SERVICES_API_KEY.Firefly)
17595
+ }
17712
17596
 
17713
17597
  const url = new URL('https://openapi.firefly.land/v1/fileverse/fetch');
17714
17598
  url.searchParams
@@ -17719,14 +17603,12 @@ async function FIREFLY() {
17719
17603
  .filter(Boolean)
17720
17604
  .join(',')
17721
17605
  );
17722
- url.searchParams.set('type', fireFlyPlaformType[platform][contentType]);
17723
- url.searchParams.set('start', String(start));
17724
- url.searchParams.set('end', String(end));
17606
+ url.searchParams.set('type', fireFlyPlaformType[platform][contentType]);
17607
+ url.searchParams.set('start', String(start));
17608
+ url.searchParams.set('end', String(end));
17725
17609
 
17726
- const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url: url.toString(), serviceName: 'Firefly', headers: { 'x-api-key': apiKey } });
17727
- const response = await fetch(finalUrl, {
17728
- method: 'GET',
17729
- headers: HEADERS,
17610
+ const response = await fetch(url.toString(), {
17611
+ headers: { 'x-api-key': apiKey }
17730
17612
  });
17731
17613
  if (!response.ok) {
17732
17614
  throw new NetworkError(SERVICES_API_KEY.Firefly, response.status)
@@ -17768,6 +17650,9 @@ async function LENS() {
17768
17650
  const apiKey = window.localStorage.getItem(
17769
17651
  SERVICES_API_KEY.Firefly
17770
17652
  );
17653
+ if (!apiKey) {
17654
+ throw new MissingApiKeyError(SERVICES_API_KEY.Firefly)
17655
+ }
17771
17656
 
17772
17657
  const url = new URL(
17773
17658
  'https://openapi.firefly.land/v1/fileverse/fetch'
@@ -17781,18 +17666,15 @@ async function LENS() {
17781
17666
  .join(',')
17782
17667
  );
17783
17668
  const typeMap = {
17784
- posts: 'lensid',
17669
+ posts: 'lensid',
17785
17670
  replies: 'lenspostid',
17786
17671
  };
17787
17672
  url.searchParams.set('type', typeMap[contentType]);
17788
17673
  url.searchParams.set('start', String(start));
17789
- url.searchParams.set('end', String(end));
17790
-
17791
- const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url: url.toString(), serviceName: 'Firefly', headers: { 'x-api-key': apiKey } });
17674
+ url.searchParams.set('end', String(end));
17792
17675
 
17793
- const response = await fetch(finalUrl, {
17794
- method: 'GET',
17795
- headers: HEADERS,
17676
+ const response = await fetch(url.toString(), {
17677
+ headers: { 'x-api-key': apiKey },
17796
17678
  });
17797
17679
  if (!response.ok) {
17798
17680
  throw new NetworkError(SERVICES_API_KEY.Firefly, response.status)
@@ -17819,7 +17701,7 @@ async function FARCASTER() {
17819
17701
  try {
17820
17702
  const [contentType, identifier, start = 0, end = 10] =
17821
17703
  argsToArray(arguments);
17822
- validateParams(farcasterParamsSchema, {
17704
+ validateParams(farcasterParamsSchema, {
17823
17705
  contentType,
17824
17706
  identifier,
17825
17707
  start,
@@ -17829,6 +17711,9 @@ async function FARCASTER() {
17829
17711
  const apiKey = window.localStorage.getItem(
17830
17712
  SERVICES_API_KEY.Firefly
17831
17713
  );
17714
+ if (!apiKey) {
17715
+ throw new MissingApiKeyError(SERVICES_API_KEY.Firefly)
17716
+ }
17832
17717
 
17833
17718
  const url = new URL(
17834
17719
  'https://openapi.firefly.land/v1/fileverse/fetch'
@@ -17842,19 +17727,16 @@ async function FARCASTER() {
17842
17727
  .join(',')
17843
17728
  );
17844
17729
  const typeMap = {
17845
- posts: 'farcasterid',
17846
- replies: 'farcasterpostid',
17847
- channels: 'farcasterchannels',
17848
- };
17730
+ posts: 'farcasterid',
17731
+ replies: 'farcasterpostid',
17732
+ channels: 'farcasterchannels',
17733
+ };
17849
17734
  url.searchParams.set('type', typeMap[contentType]);
17850
17735
  url.searchParams.set('start', String(start));
17851
- url.searchParams.set('end', String(end));
17736
+ url.searchParams.set('end', String(end));
17852
17737
 
17853
- const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url: url.toString(), serviceName: 'Firefly', headers: { 'x-api-key': apiKey } });
17854
-
17855
- const response = await fetch(finalUrl, {
17856
- method: 'GET',
17857
- headers: HEADERS,
17738
+ const response = await fetch(url.toString(), {
17739
+ headers: { 'x-api-key': apiKey },
17858
17740
  });
17859
17741
  if (!response.ok) {
17860
17742
  throw new NetworkError(
@@ -17908,14 +17790,7 @@ async function BLOCKSCOUT() {
17908
17790
  startTimestamp ?? Math.floor((Date.now() - 30 * 24 * 3600 * 1000) / 1000);
17909
17791
  const endTs = endTimestamp;
17910
17792
 
17911
- let resolvedAddress = address;
17912
- if (!isAddress$1.isAddress(resolvedAddress)) {
17913
- const ensName = resolvedAddress;
17914
- resolvedAddress = await fromEnsNameToAddress$1.fromEnsNameToAddress(ensName);
17915
- if (!resolvedAddress) {
17916
- throw new EnsError(ensName)
17917
- }
17918
- }
17793
+ const resolvedAddress = await fromEnsNameToAddress$1.validateAndGetAddress(address);
17919
17794
 
17920
17795
  const hostname = BLOCKSCOUT_CHAINS_MAP[chain];
17921
17796
 
@@ -17963,11 +17838,12 @@ async function BLOCKSCOUT() {
17963
17838
  }
17964
17839
 
17965
17840
  async function BASE() {
17966
- try {
17841
+ try {
17967
17842
  const [type, address, startDate, endDate, page, limit] = argsToArray(arguments);
17968
- validateParams(baseParamsSchema, { type, address, startDate, endDate, page, limit });
17843
+ validateParams(baseParamsSchema, { type, address, startDate, endDate, page, limit });
17969
17844
  const API_KEY = window.localStorage.getItem(SERVICES_API_KEY.Basescan);
17970
-
17845
+ if (!API_KEY) throw new MissingApiKeyError(SERVICES_API_KEY.Basescan)
17846
+
17971
17847
  return await handleScanRequest({
17972
17848
  type,
17973
17849
  address,
@@ -17980,9 +17856,9 @@ async function BASE() {
17980
17856
  chainId: CHAIN_ID_MAP.base,
17981
17857
  network: 'base'
17982
17858
  })
17983
- } catch (error) {
17984
- return errorMessageHandler(error, 'BASE')
17985
- }
17859
+ } catch (error) {
17860
+ return errorMessageHandler(error, 'BASE')
17861
+ }
17986
17862
  }
17987
17863
  async function GNOSIS() {
17988
17864
  try {
@@ -18002,6 +17878,7 @@ async function GNOSIS() {
18002
17878
  const apiKey = window.localStorage.getItem(
18003
17879
  SERVICES_API_KEY.Gnosisscan
18004
17880
  );
17881
+ if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Gnosisscan)
18005
17882
 
18006
17883
  return await handleScanRequest({
18007
17884
  type,
@@ -18022,33 +17899,27 @@ async function GNOSIS() {
18022
17899
 
18023
17900
  async function NEYNAR() {
18024
17901
  try {
18025
- const neynarParamsSchema = objectType({
18026
- username: stringType().nonempty()
18027
- });
17902
+ const neynarParamsSchema = objectType({
17903
+ username: stringType().nonempty()
17904
+ });
18028
17905
 
18029
17906
  const [username] = argsToArray(arguments);
18030
17907
 
18031
17908
  validateParams(neynarParamsSchema, { username });
18032
17909
 
18033
17910
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Neynar);
17911
+ if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Neynar)
18034
17912
 
18035
17913
  const fid = await fromUsernameToFid$1.fromUsernameToFid(username, apiKey);
18036
17914
  if (!fid) throw new ValidationError(`Invalid username: ${username}`)
18037
17915
 
18038
17916
  const url = `https://api.neynar.com/v2/farcaster/followers?fid=${fid}`;
18039
17917
 
18040
- const { URL: finalUrl, HEADERS } = getUrlAndHeaders({
18041
- url: url.toString(), serviceName: 'Neynar',
18042
- headers: {
18043
- 'x-api-key': apiKey,
18044
- 'x-neynar-experimental': 'false'
18045
- }
18046
-
18047
- });
18048
-
18049
- const response = await fetch(finalUrl, {
18050
- method: 'GET',
18051
- headers: HEADERS,
17918
+ const response = await fetch(url, {
17919
+ headers: {
17920
+ 'x-api-key': apiKey,
17921
+ 'x-neynar-experimental': 'false',
17922
+ }
18052
17923
  });
18053
17924
  if (!response.ok) {
18054
17925
  throw new NetworkError(SERVICES_API_KEY.Neynar, response.status)
@@ -18143,6 +18014,7 @@ async function ETHERSCAN() {
18143
18014
  if (!chainId) throw new ValidationError(`Invalid chain: ${chain}`)
18144
18015
 
18145
18016
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Etherscan);
18017
+ if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Etherscan)
18146
18018
 
18147
18019
  return await handleScanRequest({
18148
18020
  type,
@@ -18168,6 +18040,7 @@ async function COINGECKO() {
18168
18040
  validateParams(coingeckoParamsSchema, { category, param1, param2 });
18169
18041
 
18170
18042
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Coingecko);
18043
+ if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Coingecko)
18171
18044
 
18172
18045
  const headers = {
18173
18046
  accept: 'application/json',
@@ -18181,28 +18054,27 @@ async function COINGECKO() {
18181
18054
  break
18182
18055
  }
18183
18056
  case 'market': {
18184
- const map = { all: '', base: 'base-ecosystem', meme: 'meme-token', aiagents: 'ai-agents', bitcoin: 'bitcoin-ecosystem', ethereum: 'ethereum-ecosystem', hyperliquid: 'hyperliquid-ecosystem', pump: 'pump-ecosystem', solana: 'solana-ecosystem' };
18057
+ const map = { all:'', base:'base-ecosystem', meme:'meme-token', aiagents:'ai-agents', bitcoin:'bitcoin-ecosystem', ethereum:'ethereum-ecosystem', hyperliquid:'hyperliquid-ecosystem', pump:'pump-ecosystem', solana:'solana-ecosystem' };
18185
18058
  const _category = map[param1] || '';
18186
18059
  const trend = param2 ? `&price_change_percentage=${param2}` : '';
18187
- url = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&include_tokens=top&page=1&per_page=100${_category ? `&category=${_category}` : ''}${trend}`;
18060
+ url = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&include_tokens=top&page=1&per_page=100${_category?`&category=${_category}`:''}${trend}`;
18188
18061
  break
18189
18062
  }
18190
18063
  case 'stablecoins': {
18191
- const _category = param1 === 'all' ? 'stablecoins' : param1;
18064
+ const _category = param1==='all'? 'stablecoins' : param1;
18192
18065
  const trend = param2 ? `&price_change_percentage=${param2}` : '';
18193
18066
  url = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&category=${_category}&order=market_cap_desc&page=1&per_page=100${trend}`;
18194
18067
  break
18195
18068
  }
18196
18069
  case 'derivatives': {
18197
- url = (!param1 || param1 === 'all')
18070
+ url = (!param1 || param1==='all')
18198
18071
  ? 'https://api.coingecko.com/api/v3/derivatives'
18199
18072
  : `https://api.coingecko.com/api/v3/derivatives/exchanges/${param1}?include_tickers=all`;
18200
18073
  break
18201
18074
  }
18202
18075
  }
18203
- const {URL: finalUrl, HEADERS} = getUrlAndHeaders({url, serviceName: 'Coingecko', headers});
18204
18076
 
18205
- const res = await fetch(finalUrl, { headers: HEADERS });
18077
+ const res = await fetch(url, { headers });
18206
18078
  const json = await res.json();
18207
18079
  if (!res.ok) {
18208
18080
  const msg = json?.status?.error_message || '';
@@ -18210,17 +18082,17 @@ async function COINGECKO() {
18210
18082
  throw new NetworkError(SERVICES_API_KEY.Coingecko, res.status)
18211
18083
  }
18212
18084
 
18213
- if (category === 'price') {
18085
+ if (category==='price') {
18214
18086
  const out = {};
18215
18087
  for (const [token, prices] of Object.entries(json))
18216
- for (const [cur, val] of Object.entries(prices))
18217
- out[`${token.charAt(0).toUpperCase() + token.slice(1)}_${cur.toUpperCase()}`] = val;
18088
+ for (const [cur,val] of Object.entries(prices))
18089
+ out[`${token.charAt(0).toUpperCase()+token.slice(1)}_${cur.toUpperCase()}`]=val;
18218
18090
  return [out]
18219
18091
  }
18220
18092
 
18221
18093
  const data = Array.isArray(json) ? json : [json];
18222
- return data.map(item => {
18223
- const flat = {};
18094
+ return data.map(item=>{
18095
+ const flat={};
18224
18096
  for (const [key, value] of Object.entries(item)) {
18225
18097
  if (typeof value !== 'object' || value === null) {
18226
18098
  flat[key] = value;
@@ -18228,8 +18100,8 @@ async function COINGECKO() {
18228
18100
  }
18229
18101
  return flat
18230
18102
  })
18231
- } catch (err) {
18232
- return errorMessageHandler(err, 'COINGECKO')
18103
+ } catch(err) {
18104
+ return errorMessageHandler(err,'COINGECKO')
18233
18105
  }
18234
18106
  }
18235
18107
 
@@ -18240,30 +18112,25 @@ async function EOA() {
18240
18112
  validateParams(eoaParamsSchema, { addresses, category, chains, startTime, endTime, page, offset });
18241
18113
 
18242
18114
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Etherscan);
18115
+ if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Etherscan)
18243
18116
 
18244
- const INPUTS = addresses.split(',').map(s => s.trim()).filter(Boolean);
18245
- const CHAINS = chains.split(',').map(s => s.trim()).filter(Boolean);
18117
+ const INPUTS = addresses.split(',').map(s=>s.trim()).filter(Boolean);
18118
+ const CHAINS = chains.split(',').map(s=>s.trim()).filter(Boolean);
18246
18119
 
18247
18120
  const ADDRESS_MAP = {};
18248
18121
  for (const inp of INPUTS) {
18249
18122
  if (isAddress$1.isAddress(inp)) {
18250
18123
  ADDRESS_MAP[inp.toLowerCase()] = null;
18251
18124
  } else {
18252
- const ens = inp;
18253
- const resolved = await fromEnsNameToAddress$1.fromEnsNameToAddress(ens);
18254
- if (!resolved) throw new EnsError(ens)
18255
- ADDRESS_MAP[resolved.toLowerCase()] = ens;
18125
+ const _address = await fromEnsNameToAddress$1.validateAndGetAddress(inp);
18126
+ ADDRESS_MAP[_address.toLowerCase()] = _address;
18256
18127
  }
18257
18128
  }
18258
18129
  const ADDRS = Object.keys(ADDRESS_MAP);
18259
18130
  const out = [];
18260
18131
 
18261
18132
  async function fetchJSON(url) {
18262
- const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url, serviceName: 'Etherscan', headers: {} });
18263
- const res = await fetch(finalUrl, {
18264
- method: 'GET',
18265
- headers: HEADERS,
18266
- });
18133
+ const res = await fetch(url);
18267
18134
  if (!res.ok) throw new NetworkError(SERVICES_API_KEY.Etherscan, res.status)
18268
18135
  const json = await res.json();
18269
18136
 
@@ -18281,15 +18148,15 @@ async function EOA() {
18281
18148
 
18282
18149
  if (category === 'balance') {
18283
18150
  // chunk 20
18284
- for (let i = 0; i < ADDRS.length; i += 20) {
18285
- const slice = ADDRS.slice(i, i + 20).join(',');
18151
+ for (let i=0; i<ADDRS.length; i+=20) {
18152
+ const slice = ADDRS.slice(i,i+20).join(',');
18286
18153
  const url =
18287
- `https://api.etherscan.io/v2/api?chainid=${chainId}` +
18288
- `&module=account&action=addresstokenbalance&address=${slice}` +
18154
+ `https://api.etherscan.io/v2/api?chainid=${chainId}`+
18155
+ `&module=account&action=addresstokenbalance&address=${slice}`+
18289
18156
  `&page=${page}&offset=${offset}&apikey=${apiKey}`;
18290
18157
  const data = await fetchJSON(url);
18291
18158
  if (!Array.isArray(data)) return data
18292
- data.forEach((item, idx) => out.push({ chain, address: ADDRS[i + idx], name: ADDRESS_MAP[ADDRS[i + idx]], ...item }));
18159
+ data.forEach((item, idx) => out.push({ chain, address: ADDRS[i+idx], name: ADDRESS_MAP[ADDRS[i+idx]], ...item }));
18293
18160
  }
18294
18161
  } else {
18295
18162
  // txns
@@ -18299,9 +18166,9 @@ async function EOA() {
18299
18166
  if (!eb) throw new ValidationError(`Invalid endTime: ${endTime}`)
18300
18167
  for (const addr of ADDRS) {
18301
18168
  const url =
18302
- `https://api.etherscan.io/v2/api?chainid=${chainId}` +
18303
- `&module=account&action=tokentx&address=${addr}` +
18304
- `&startblock=${sb}&endblock=${eb}` +
18169
+ `https://api.etherscan.io/v2/api?chainid=${chainId}`+
18170
+ `&module=account&action=tokentx&address=${addr}`+
18171
+ `&startblock=${sb}&endblock=${eb}`+
18305
18172
  `&page=${page}&offset=${offset}&sort=asc&apikey=${apiKey}`;
18306
18173
  const data = await fetchJSON(url);
18307
18174
  if (!Array.isArray(data)) return data
@@ -18330,22 +18197,21 @@ async function SAFE() {
18330
18197
  validateParams(safeParamsSchema, { address, utility, chain, limit, offset });
18331
18198
 
18332
18199
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Safe);
18200
+ if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Safe)
18333
18201
 
18334
18202
  const chainId = SAFE_CHAIN_MAP[chain];
18335
18203
  if (!chainId) throw new ValidationError(`Invalid chain: ${chain}`)
18336
18204
 
18337
- let resolved = address;
18338
- if (!isAddress$1.isAddress(resolved)) {
18339
- const ens = resolved;
18340
- resolved = await fromEnsNameToAddress$1.fromEnsNameToAddress(ens);
18341
- if (!resolved) throw new EnsError(ens)
18342
- }
18205
+
18206
+
18207
+
18208
+ const resolved = await fromEnsNameToAddress$1.validateAndGetAddress(address);
18343
18209
 
18344
18210
 
18345
18211
  const url = `https://api.safe.global/tx-service/${chainId}/api/v2/safes/${resolved}/multisig-transactions?limit=${limit}&offset=${offset}`;
18346
18212
 
18347
- const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url, serviceName: 'Etherscan', headers: { Authorization: `Bearer ${apiKey}` } });
18348
- const res = await fetch(finalUrl, { headers: HEADERS });
18213
+
18214
+ const res = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
18349
18215
  if (!res.ok) throw new NetworkError(SERVICES_API_KEY.Safe, res.status)
18350
18216
  const json = await res.json();
18351
18217
 
@@ -18366,6 +18232,7 @@ async function DEFILLAMA() {
18366
18232
  const [category] = argsToArray(arguments);
18367
18233
  validateParams(defillamaParamsSchema, { category });
18368
18234
  const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Defillama);
18235
+ if (!apiKey) throw new MissingApiKeyError(SERVICES_API_KEY.Defillama)
18369
18236
  const url = CATEGORY_URLS[category];
18370
18237
  if (!url) throw new ValidationError(`Invalid category: ${category}`)
18371
18238
  const res = await fetch(url);
@@ -18374,20 +18241,20 @@ async function DEFILLAMA() {
18374
18241
 
18375
18242
  switch (category) {
18376
18243
  case 'protocols':
18377
- json = Array.isArray(json) ? json.slice(0, 500) : [];
18244
+ json = Array.isArray(json) ? json.slice(0,500) : [];
18378
18245
  break
18379
18246
  case 'yields':
18380
- json = Array.isArray(json.data) ? json.data.slice(0, 500) : [];
18247
+ json = Array.isArray(json.data) ? json.data.slice(0,500) : [];
18381
18248
  break
18382
18249
  case 'dex':
18383
18250
  case 'fees':
18384
- json = Array.isArray(json.protocols) ? json.protocols.slice(0, 500) : [];
18251
+ json = Array.isArray(json.protocols) ? json.protocols.slice(0,500) : [];
18385
18252
  break
18386
18253
  }
18387
18254
 
18388
18255
  return (Array.isArray(json) ? json : [json]).map(item => {
18389
18256
  const out = {};
18390
- for (const [k, v] of Object.entries(item)) {
18257
+ for (const [k,v] of Object.entries(item)) {
18391
18258
  if (v === null || typeof v !== 'object') out[k] = v;
18392
18259
  }
18393
18260
  return out
@@ -18423,7 +18290,7 @@ async function UNISWAP() {
18423
18290
  // flatten nested
18424
18291
  return json.map(item => {
18425
18292
  const flat = {};
18426
- Object.entries(item).forEach(([k, v]) => {
18293
+ Object.entries(item).forEach(([k,v]) => {
18427
18294
  if (v === null || typeof v !== 'object') flat[k] = v;
18428
18295
  });
18429
18296
  return flat