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