@fileverse-dev/formulajs 4.4.11-mod-82 → 4.4.11-mod-83-patch-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/formula.js +1856 -1858
- package/lib/browser/formula.min.js +2 -2
- package/lib/browser/formula.min.js.map +1 -1
- package/lib/cjs/index.cjs +992 -1043
- package/lib/esm/crypto-constants.mjs +655 -859
- package/lib/esm/index.mjs +992 -1043
- package/package.json +2 -2
- package/types/cjs/index.d.cts +4 -4
- package/types/esm/index.d.mts +4 -4
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',
|
|
@@ -13187,419 +13186,86 @@ class InvalidApiKeyError extends Error {
|
|
|
13187
13186
|
}
|
|
13188
13187
|
}
|
|
13189
13188
|
|
|
13190
|
-
|
|
13191
|
-
|
|
13192
|
-
|
|
13193
|
-
|
|
13194
|
-
|
|
13195
|
-
|
|
13196
|
-
|
|
13197
|
-
|
|
13198
|
-
|
|
13199
|
-
url: `${fileverseProxyUrl}/proxy`,
|
|
13200
|
-
removeParams: ['apikey']
|
|
13201
|
-
},
|
|
13202
|
-
Basescan: {
|
|
13203
|
-
url: `${fileverseProxyUrl}/proxy`,
|
|
13204
|
-
removeParams: ['apikey']
|
|
13205
|
-
},
|
|
13206
|
-
Gnosisscan: {
|
|
13207
|
-
url: `${fileverseProxyUrl}/proxy`,
|
|
13208
|
-
removeParams: ['apikey']
|
|
13209
|
-
},
|
|
13210
|
-
Coingecko: {
|
|
13211
|
-
url: `${fileverseProxyUrl}/proxy`,
|
|
13212
|
-
removeParams: ['apikey']
|
|
13213
|
-
},
|
|
13214
|
-
Firefly: {
|
|
13215
|
-
url: `${fileverseProxyUrl}/proxy`,
|
|
13216
|
-
removeParams: ['apikey']
|
|
13217
|
-
},
|
|
13218
|
-
Neynar: {
|
|
13219
|
-
url: `${fileverseProxyUrl}/proxy`,
|
|
13220
|
-
removeParams: ['api_key']
|
|
13221
|
-
},
|
|
13222
|
-
Safe: {
|
|
13223
|
-
url: `${fileverseProxyUrl}/proxy`,
|
|
13224
|
-
removeParams: ['api_key']
|
|
13225
|
-
},
|
|
13226
|
-
Defillama: {
|
|
13227
|
-
url: `${fileverseProxyUrl}/proxy`,
|
|
13228
|
-
removeParams: ['api_key']
|
|
13229
|
-
},
|
|
13230
|
-
GnosisPay: {
|
|
13231
|
-
url: `${fileverseProxyUrl}/proxy`,
|
|
13232
|
-
removeParams: ['api_key']
|
|
13233
|
-
},
|
|
13234
|
-
// Add more services as needed. It can be direct url instead of ENV variable
|
|
13235
|
-
// ANOTHER_SERVICE: "https://another-proxy-url.com"
|
|
13236
|
-
};
|
|
13237
|
-
}
|
|
13238
|
-
return PROXY_MAP;
|
|
13239
|
-
}
|
|
13240
|
-
|
|
13241
|
-
// const fileverseProxyUrl = `${window.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`
|
|
13242
|
-
// // Proxy map configuration
|
|
13243
|
-
// const PROXY_MAP = {
|
|
13244
|
-
// Etherscan: {
|
|
13245
|
-
// url: `${process.env.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`,
|
|
13246
|
-
// removeParams: ['apikey']
|
|
13247
|
-
// },
|
|
13248
|
-
// Basescan: {
|
|
13249
|
-
// url: `${process.env.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`,
|
|
13250
|
-
// removeParams: ['apikey']
|
|
13251
|
-
// },
|
|
13252
|
-
// Gnosisscan: {
|
|
13253
|
-
// url: `${process.env.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`,
|
|
13254
|
-
// removeParams: ['apikey']
|
|
13255
|
-
// },
|
|
13256
|
-
// Coingecko: {
|
|
13257
|
-
// url: `${process.env.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`,
|
|
13258
|
-
// removeParams: ['apikey']
|
|
13259
|
-
// },
|
|
13260
|
-
// Firefly: {
|
|
13261
|
-
// url: `${process.env.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`,
|
|
13262
|
-
// removeParams: ['apikey']
|
|
13263
|
-
// },
|
|
13264
|
-
// Neynar: {
|
|
13265
|
-
// url: `${process.env.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`,
|
|
13266
|
-
// removeParams: ['api_key']
|
|
13267
|
-
// },
|
|
13268
|
-
// Safe: {
|
|
13269
|
-
// url: `${process.env.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`,
|
|
13270
|
-
// removeParams: ['api_key']
|
|
13271
|
-
// },
|
|
13272
|
-
// Defillama: {
|
|
13273
|
-
// url: `${process.env.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`,
|
|
13274
|
-
// removeParams: ['api_key']
|
|
13275
|
-
// },
|
|
13276
|
-
// GnosisPay: {
|
|
13277
|
-
// url: `${process.env.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`,
|
|
13278
|
-
// removeParams: ['api_key']
|
|
13279
|
-
// },
|
|
13280
|
-
// // Add more services as needed. It can be direct url instead of ENV variable
|
|
13281
|
-
// // ANOTHER_SERVICE: "https://another-proxy-url.com"
|
|
13282
|
-
// };
|
|
13283
|
-
|
|
13284
|
-
/**
|
|
13285
|
-
* Removes specified parameters from a URL
|
|
13286
|
-
* @param {string} url - The original URL
|
|
13287
|
-
* @param {string[]} paramsToRemove - Array of parameter names to remove
|
|
13288
|
-
* @returns {string} URL with specified parameters removed
|
|
13289
|
-
*/
|
|
13290
|
-
function removeUrlParams(url, paramsToRemove) {
|
|
13291
|
-
if (!paramsToRemove || paramsToRemove.length === 0) {
|
|
13292
|
-
return url;
|
|
13189
|
+
const errorMessageHandler = (err, functionName) => {
|
|
13190
|
+
|
|
13191
|
+
switch (true) {
|
|
13192
|
+
case err instanceof ValidationError : {
|
|
13193
|
+
return {
|
|
13194
|
+
message: err.message,
|
|
13195
|
+
functionName,
|
|
13196
|
+
type: ERROR_MESSAGES_FLAG.INVALID_PARAM
|
|
13197
|
+
}
|
|
13293
13198
|
}
|
|
13294
13199
|
|
|
13295
|
-
|
|
13296
|
-
|
|
13297
|
-
|
|
13298
|
-
|
|
13299
|
-
|
|
13300
|
-
|
|
13301
|
-
});
|
|
13302
|
-
|
|
13303
|
-
return urlObj.toString();
|
|
13304
|
-
}
|
|
13305
|
-
|
|
13306
|
-
/**
|
|
13307
|
-
* Handles URL routing through proxy or direct API calls
|
|
13308
|
-
* @param {string} url - The original API URL
|
|
13309
|
-
* @param {string} serviceName - [OPTIONAL] The name of the service (e.g., 'EOA')
|
|
13310
|
-
* @param {object} headers - [OPTIONAL] The name of the service (e.g., 'EOA')
|
|
13311
|
-
* @returns {Object} Object containing URL and HEADERS for the fetch request
|
|
13312
|
-
*/
|
|
13313
|
-
function getUrlAndHeaders({ url, serviceName, headers = {} }) {
|
|
13314
|
-
const proxyMap = initializeProxyMap();
|
|
13315
|
-
// Check if proxy is enabled in localStorage
|
|
13316
|
-
const apiKeyLS = window.localStorage.getItem(SERVICES_API_KEY[serviceName]);
|
|
13317
|
-
const isProxyModeEnabledValue = apiKeyLS === 'DEFAULT_PROXY_MODE';
|
|
13318
|
-
|
|
13319
|
-
// Check if proxy URL exists for this service
|
|
13320
|
-
const proxyConfig = proxyMap[serviceName];
|
|
13321
|
-
|
|
13322
|
-
if (!proxyConfig && SERVICES_API_KEY[serviceName] && (!apiKeyLS || apiKeyLS === '')) {
|
|
13323
|
-
throw new MissingApiKeyError(SERVICES_API_KEY[serviceName])
|
|
13324
|
-
}
|
|
13200
|
+
case err instanceof MissingApiKeyError :
|
|
13201
|
+
return {
|
|
13202
|
+
message: err.message,
|
|
13203
|
+
functionName,
|
|
13204
|
+
type: ERROR_MESSAGES_FLAG.MISSING_KEY
|
|
13205
|
+
}
|
|
13325
13206
|
|
|
13326
|
-
|
|
13327
|
-
|
|
13328
|
-
|
|
13329
|
-
|
|
13207
|
+
case err instanceof RateLimitError:
|
|
13208
|
+
return {
|
|
13209
|
+
message: err.message,
|
|
13210
|
+
functionName,
|
|
13211
|
+
type: ERROR_MESSAGES_FLAG.RATE_LIMIT,
|
|
13212
|
+
apiKeyName: err.api
|
|
13213
|
+
}
|
|
13330
13214
|
|
|
13215
|
+
case err instanceof NetworkError:
|
|
13216
|
+
if(err.status === 429){
|
|
13331
13217
|
return {
|
|
13332
|
-
|
|
13333
|
-
|
|
13334
|
-
|
|
13335
|
-
|
|
13336
|
-
|
|
13337
|
-
|
|
13338
|
-
|
|
13339
|
-
|
|
13340
|
-
|
|
13341
|
-
|
|
13342
|
-
|
|
13343
|
-
|
|
13344
|
-
|
|
13345
|
-
}
|
|
13346
|
-
};
|
|
13347
|
-
}
|
|
13348
|
-
|
|
13349
|
-
const fromTimeStampToBlock = async (timestamp, chain, apiKey) => {
|
|
13350
|
-
if (!timestamp || !chain) return
|
|
13351
|
-
const chainId = CHAIN_ID_MAP[chain];
|
|
13352
|
-
const url = `https://api.etherscan.io/v2/api?module=block&action=getblocknobytime×tamp=${timestamp}&closest=before&apikey=${apiKey}&chainId=${chainId}`;
|
|
13353
|
-
const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url, serviceName: 'Etherscan', headers: {} });
|
|
13354
|
-
const res = await fetch(finalUrl, {
|
|
13355
|
-
method: 'GET',
|
|
13356
|
-
headers: HEADERS,
|
|
13357
|
-
});
|
|
13358
|
-
const json = await res.json();
|
|
13359
|
-
return parseInt(json.result);
|
|
13360
|
-
|
|
13361
|
-
};
|
|
13362
|
-
|
|
13363
|
-
var fromTimestampToBlock = {
|
|
13364
|
-
fromTimeStampToBlock
|
|
13365
|
-
};
|
|
13218
|
+
message: err.message,
|
|
13219
|
+
functionName,
|
|
13220
|
+
type: ERROR_MESSAGES_FLAG.RATE_LIMIT,
|
|
13221
|
+
apiKeyName: err.api
|
|
13222
|
+
}
|
|
13223
|
+
} else {
|
|
13224
|
+
return {
|
|
13225
|
+
message: err.message,
|
|
13226
|
+
functionName,
|
|
13227
|
+
type: ERROR_MESSAGES_FLAG.NETWORK_ERROR,
|
|
13228
|
+
apiKeyName: err.api
|
|
13229
|
+
}
|
|
13230
|
+
}
|
|
13366
13231
|
|
|
13367
|
-
|
|
13368
|
-
|
|
13369
|
-
|
|
13370
|
-
|
|
13371
|
-
|
|
13372
|
-
}
|
|
13232
|
+
case err instanceof EnsError:
|
|
13233
|
+
return {
|
|
13234
|
+
message: err.message,
|
|
13235
|
+
functionName,
|
|
13236
|
+
type: ERROR_MESSAGES_FLAG.ENS
|
|
13237
|
+
}
|
|
13373
13238
|
|
|
13374
|
-
|
|
13375
|
-
|
|
13376
|
-
|
|
13239
|
+
case err instanceof InvalidApiKeyError:
|
|
13240
|
+
return {
|
|
13241
|
+
message: err.message,
|
|
13242
|
+
functionName,
|
|
13243
|
+
type: ERROR_MESSAGES_FLAG.INVALID_API_KEY,
|
|
13244
|
+
apiKeyName: err.api
|
|
13245
|
+
}
|
|
13377
13246
|
|
|
13378
|
-
|
|
13379
|
-
|
|
13247
|
+
default:
|
|
13248
|
+
return {
|
|
13249
|
+
message: 'An unexpected error occured',
|
|
13250
|
+
functionName,
|
|
13251
|
+
type: ERROR_MESSAGES_FLAG.DEFAULT,
|
|
13252
|
+
reason: err.message || err
|
|
13253
|
+
}
|
|
13254
|
+
}
|
|
13380
13255
|
};
|
|
13381
13256
|
|
|
13382
|
-
/* global document */
|
|
13383
|
-
/* global window */
|
|
13384
|
-
/* global ethers */
|
|
13385
|
-
|
|
13386
13257
|
|
|
13387
13258
|
|
|
13388
|
-
async function fromEnsNameToAddress(name) {
|
|
13389
|
-
if (typeof ethers === 'undefined') {
|
|
13390
|
-
await new Promise((resolve, reject) => {
|
|
13391
|
-
const script = document.createElement('script');
|
|
13392
|
-
script.src = 'https://cdn.jsdelivr.net/npm/ethers@6.10.0/dist/ethers.umd.min.js';
|
|
13393
|
-
script.onload = resolve;
|
|
13394
|
-
script.onerror = reject;
|
|
13395
|
-
document.head.appendChild(script);
|
|
13396
|
-
});
|
|
13397
|
-
}
|
|
13398
|
-
|
|
13399
|
-
const ALCHEMY_KEY = window.localStorage.getItem(UTILITY.ALCHEMY_API_KEY);
|
|
13400
|
-
if (!ALCHEMY_KEY) {
|
|
13401
|
-
console.error('alchemy api key missing');
|
|
13402
|
-
return null
|
|
13403
|
-
}
|
|
13404
|
-
const provider = new ethers.AlchemyProvider('mainnet', ALCHEMY_KEY);
|
|
13405
13259
|
|
|
13406
|
-
|
|
13407
|
-
|
|
13408
|
-
|
|
13409
|
-
|
|
13410
|
-
|
|
13411
|
-
|
|
13260
|
+
function validateParams(schema, rawParams) {
|
|
13261
|
+
const result = schema.safeParse(rawParams);
|
|
13262
|
+
if (!result.success) {
|
|
13263
|
+
const issue = result.error.issues[0];
|
|
13264
|
+
throw new ValidationError(
|
|
13265
|
+
issue.message
|
|
13266
|
+
)
|
|
13412
13267
|
}
|
|
13413
|
-
|
|
13414
|
-
const validateAndGetAddress = async (address) => {
|
|
13415
|
-
if(isAddress$1.isAddress(address)) return address
|
|
13416
|
-
|
|
13417
|
-
const resolvedAddress = await fromEnsNameToAddress(address);
|
|
13418
|
-
if(resolvedAddress) return resolvedAddress
|
|
13419
|
-
throw new ValidationError("Invalid address")
|
|
13420
|
-
};
|
|
13421
|
-
|
|
13422
|
-
var fromEnsNameToAddress$1 = {
|
|
13423
|
-
validateAndGetAddress
|
|
13424
|
-
};
|
|
13425
|
-
|
|
13426
|
-
async function handleScanRequest({
|
|
13427
|
-
type,
|
|
13428
|
-
address,
|
|
13429
|
-
startDate,
|
|
13430
|
-
endDate,
|
|
13431
|
-
page = 1,
|
|
13432
|
-
offset = 10,
|
|
13433
|
-
apiKey,
|
|
13434
|
-
functionName,
|
|
13435
|
-
chainId,
|
|
13436
|
-
network
|
|
13437
|
-
}) {
|
|
13438
|
-
const API_INFO_MAP = {
|
|
13439
|
-
BASE: { url: 'https://api.basescan.org/api', apiKeyName: SERVICES_API_KEY.Basescan },
|
|
13440
|
-
ETHERSCAN: { url: 'https://api.etherscan.io/v2/api', apiKeyName: SERVICES_API_KEY.Etherscan },
|
|
13441
|
-
GNOSIS: { url: 'https://api.gnosisscan.io/api', apiKeyName: SERVICES_API_KEY.Gnosisscan }
|
|
13442
|
-
};
|
|
13443
|
-
|
|
13444
|
-
if (type !== 'gas') {
|
|
13445
|
-
address = await fromEnsNameToAddress$1.validateAndGetAddress(address);
|
|
13446
|
-
}
|
|
13447
|
-
|
|
13448
|
-
const apiInfo = API_INFO_MAP[functionName];
|
|
13449
|
-
const baseUrl = apiInfo?.url;
|
|
13450
|
-
if (!baseUrl) throw new ValidationError(`Api not found for: ${functionName}`)
|
|
13451
|
-
|
|
13452
|
-
|
|
13453
|
-
const ACTION_MAP = {
|
|
13454
|
-
'all-txns': 'txlist',
|
|
13455
|
-
'token-txns': 'tokentx',
|
|
13456
|
-
'nft-txns': 'tokennfttx',
|
|
13457
|
-
'gas': 'gasoracle'
|
|
13458
|
-
};
|
|
13459
|
-
|
|
13460
|
-
const action = ACTION_MAP[type];
|
|
13461
|
-
if (!action) throw new ValidationError(`Invalid type: ${type}`)
|
|
13462
|
-
|
|
13463
|
-
const module = action === 'gasoracle' ? 'gastracker' : 'account';
|
|
13464
|
-
let url = `${baseUrl}?chainid=${chainId}&module=${module}&action=${action}&apikey=${apiKey}`;
|
|
13465
|
-
|
|
13466
|
-
if (['all-txns', 'token-txns', 'nft-txns'].includes(type)) {
|
|
13467
|
-
url += `&address=${address}&startblock=0&endblock=99999999&sort=asc`;
|
|
13468
|
-
|
|
13469
|
-
if (!isNaN(startDate) && !isNaN(endDate)) {
|
|
13470
|
-
const [startBlock, endBlock] = await Promise.all([
|
|
13471
|
-
fromTimestampToBlock.fromTimeStampToBlock(toTimestamp(startDate), network, apiKey),
|
|
13472
|
-
fromTimestampToBlock.fromTimeStampToBlock(toTimestamp(endDate), network, apiKey)
|
|
13473
|
-
]);
|
|
13474
|
-
url += `&startblock=${startBlock || '0'}&endblock=${endBlock || '99999999'}`;
|
|
13475
|
-
}
|
|
13476
|
-
url += `&page=${page}&offset=${offset}`;
|
|
13477
|
-
}
|
|
13478
|
-
const { URL: finalUrl, HEADERS } = getUrlAndHeaders({url, serviceName: apiInfo.apiKeyName, headers: {}});
|
|
13479
|
-
const res = await fetch(finalUrl, {
|
|
13480
|
-
method: 'GET',
|
|
13481
|
-
headers: HEADERS,
|
|
13482
|
-
});
|
|
13483
|
-
if (!res.ok) {
|
|
13484
|
-
throw new NetworkError(apiInfo.apiKeyName, res.status)
|
|
13485
|
-
}
|
|
13486
|
-
const json = await res.json();
|
|
13487
|
-
|
|
13488
|
-
if (typeof json.result === 'string') {
|
|
13489
|
-
if (json.result.includes('Invalid API Key')){
|
|
13490
|
-
throw new InvalidApiKeyError(apiInfo.apiKeyName)
|
|
13491
|
-
}
|
|
13492
|
-
|
|
13493
|
-
if (json.result.includes('Max rate limit reached'))
|
|
13494
|
-
throw new RateLimitError(apiInfo.apiKeyName)
|
|
13495
|
-
}
|
|
13496
|
-
|
|
13497
|
-
return type === 'gas' && !Array.isArray(json.result) ? [json.result] : json.result
|
|
13498
|
-
}
|
|
13499
|
-
|
|
13500
|
-
const fromUsernameToFid = async (username, apiKey) => {
|
|
13501
|
-
if (!username) return null
|
|
13502
|
-
const url = `https://api.neynar.com/v2/farcaster/user/search/?q=${username}&limit=5`;
|
|
13503
|
-
const { URL: finalUrl, HEADERS } = getUrlAndHeaders({
|
|
13504
|
-
url, serviceName: 'Neynar', headers: {
|
|
13505
|
-
'x-api-key': apiKey,
|
|
13506
|
-
'x-neynar-experimental': 'false'
|
|
13507
|
-
}
|
|
13508
|
-
});
|
|
13509
|
-
|
|
13510
|
-
const res = await fetch(finalUrl, {
|
|
13511
|
-
method: 'GET',
|
|
13512
|
-
headers: HEADERS,
|
|
13513
|
-
});
|
|
13514
|
-
const json = await res.json();
|
|
13515
|
-
const users = json.result ? json.result.users : [];
|
|
13516
|
-
const user = users.find(user => user.username === username);
|
|
13517
|
-
return user && user.fid || null;
|
|
13518
|
-
};
|
|
13519
|
-
var fromUsernameToFid$1 = {
|
|
13520
|
-
fromUsernameToFid
|
|
13521
|
-
};
|
|
13522
|
-
|
|
13523
|
-
const errorMessageHandler = (err, functionName) => {
|
|
13524
|
-
|
|
13525
|
-
switch (true) {
|
|
13526
|
-
case err instanceof ValidationError : {
|
|
13527
|
-
return {
|
|
13528
|
-
message: err.message,
|
|
13529
|
-
functionName,
|
|
13530
|
-
type: ERROR_MESSAGES_FLAG.INVALID_PARAM
|
|
13531
|
-
}
|
|
13532
|
-
}
|
|
13533
|
-
|
|
13534
|
-
case err instanceof MissingApiKeyError :
|
|
13535
|
-
return {
|
|
13536
|
-
message: err.message,
|
|
13537
|
-
functionName,
|
|
13538
|
-
type: ERROR_MESSAGES_FLAG.MISSING_KEY
|
|
13539
|
-
}
|
|
13540
|
-
|
|
13541
|
-
case err instanceof RateLimitError:
|
|
13542
|
-
return {
|
|
13543
|
-
message: err.message,
|
|
13544
|
-
functionName,
|
|
13545
|
-
type: ERROR_MESSAGES_FLAG.RATE_LIMIT,
|
|
13546
|
-
apiKeyName: err.api
|
|
13547
|
-
}
|
|
13548
|
-
|
|
13549
|
-
case err instanceof NetworkError:
|
|
13550
|
-
if(err.status === 429){
|
|
13551
|
-
return {
|
|
13552
|
-
message: err.message,
|
|
13553
|
-
functionName,
|
|
13554
|
-
type: ERROR_MESSAGES_FLAG.RATE_LIMIT,
|
|
13555
|
-
apiKeyName: err.api
|
|
13556
|
-
}
|
|
13557
|
-
} else {
|
|
13558
|
-
return {
|
|
13559
|
-
message: err.message,
|
|
13560
|
-
functionName,
|
|
13561
|
-
type: ERROR_MESSAGES_FLAG.NETWORK_ERROR,
|
|
13562
|
-
apiKeyName: err.api
|
|
13563
|
-
}
|
|
13564
|
-
}
|
|
13565
|
-
|
|
13566
|
-
case err instanceof EnsError:
|
|
13567
|
-
return {
|
|
13568
|
-
message: err.message,
|
|
13569
|
-
functionName,
|
|
13570
|
-
type: ERROR_MESSAGES_FLAG.ENS
|
|
13571
|
-
}
|
|
13572
|
-
|
|
13573
|
-
case err instanceof InvalidApiKeyError:
|
|
13574
|
-
return {
|
|
13575
|
-
message: err.message,
|
|
13576
|
-
functionName,
|
|
13577
|
-
type: ERROR_MESSAGES_FLAG.INVALID_API_KEY,
|
|
13578
|
-
apiKeyName: err.api
|
|
13579
|
-
}
|
|
13580
|
-
|
|
13581
|
-
default:
|
|
13582
|
-
return {
|
|
13583
|
-
message: 'An unexpected error occured',
|
|
13584
|
-
functionName,
|
|
13585
|
-
type: ERROR_MESSAGES_FLAG.DEFAULT,
|
|
13586
|
-
reason: err.message || err
|
|
13587
|
-
}
|
|
13588
|
-
}
|
|
13589
|
-
};
|
|
13590
|
-
|
|
13591
|
-
|
|
13592
|
-
|
|
13593
|
-
|
|
13594
|
-
function validateParams(schema, rawParams) {
|
|
13595
|
-
const result = schema.safeParse(rawParams);
|
|
13596
|
-
if (!result.success) {
|
|
13597
|
-
const issue = result.error.issues[0];
|
|
13598
|
-
throw new ValidationError(
|
|
13599
|
-
issue.message
|
|
13600
|
-
)
|
|
13601
|
-
}
|
|
13602
|
-
return result.data
|
|
13268
|
+
return result.data
|
|
13603
13269
|
}
|
|
13604
13270
|
|
|
13605
13271
|
var util;
|
|
@@ -17518,51 +17184,50 @@ ZodOptional.create;
|
|
|
17518
17184
|
ZodNullable.create;
|
|
17519
17185
|
const preprocessType = ZodEffects.createWithPreprocess;
|
|
17520
17186
|
|
|
17521
|
-
const
|
|
17522
|
-
|
|
17523
|
-
|
|
17524
|
-
|
|
17525
|
-
|
|
17526
|
-
end: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"end" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17187
|
+
const aaveParamsSchema = objectType({
|
|
17188
|
+
graphType: enumType(['v2','v2-raw']),
|
|
17189
|
+
category: enumType(['tokens','markets']),
|
|
17190
|
+
param1: stringType().nonempty(),
|
|
17191
|
+
param2: stringType().optional(),
|
|
17527
17192
|
});
|
|
17528
17193
|
|
|
17529
|
-
|
|
17530
|
-
|
|
17531
|
-
contentType: enumType(['posts', 'replies']),
|
|
17532
|
-
identifier: stringType().nonempty(),
|
|
17533
|
-
start: numberType().int().nonnegative().default(0),
|
|
17534
|
-
end: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"end" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17535
|
-
});
|
|
17194
|
+
async function AAVE() {
|
|
17195
|
+
try {
|
|
17536
17196
|
|
|
17537
|
-
const
|
|
17538
|
-
farcasterSchema,
|
|
17539
|
-
lensSchema,
|
|
17540
|
-
]);
|
|
17541
|
-
const fireFlyPlaformType = {
|
|
17542
|
-
farcaster: {
|
|
17543
|
-
posts: 'farcasterid',
|
|
17544
|
-
replies: 'farcasterpostid',
|
|
17545
|
-
channels: 'farcasterchannels'
|
|
17546
|
-
},
|
|
17547
|
-
lens: {
|
|
17548
|
-
posts: 'lensid',
|
|
17549
|
-
replies: 'lenspostid'
|
|
17550
|
-
}
|
|
17551
|
-
};
|
|
17197
|
+
const [graphType, category, param1, param2] = argsToArray(arguments);
|
|
17552
17198
|
|
|
17553
|
-
const lensParamsSchema = objectType({
|
|
17554
|
-
contentType: enumType(['posts', 'replies']),
|
|
17555
|
-
identifier: stringType().nonempty(),
|
|
17556
|
-
start: numberType().int().nonnegative().default(0),
|
|
17557
|
-
end: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"end" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17558
|
-
});
|
|
17559
17199
|
|
|
17560
|
-
|
|
17561
|
-
|
|
17562
|
-
|
|
17563
|
-
|
|
17564
|
-
|
|
17565
|
-
|
|
17200
|
+
validateParams(aaveParamsSchema, { graphType, category, param1, param2 });
|
|
17201
|
+
|
|
17202
|
+
const baseUrl = 'https://onchain-proxy.fileverse.io/third-party';
|
|
17203
|
+
const url =
|
|
17204
|
+
`${baseUrl}` +
|
|
17205
|
+
`?service=aave` +
|
|
17206
|
+
`&graphType=${encodeURIComponent(graphType)}` +
|
|
17207
|
+
`&category=${encodeURIComponent(category)}` +
|
|
17208
|
+
`&input1=${encodeURIComponent(param1)}` +
|
|
17209
|
+
(param2 ? `&input2=${encodeURIComponent(param2)}` : '');
|
|
17210
|
+
|
|
17211
|
+
const res = await fetch(url);
|
|
17212
|
+
if (!res.ok) {
|
|
17213
|
+
throw new NetworkError('AAVE', res.status)
|
|
17214
|
+
}
|
|
17215
|
+
|
|
17216
|
+
const json = await res.json();
|
|
17217
|
+
if (Array.isArray(json)) {
|
|
17218
|
+
return json.map(item => {
|
|
17219
|
+
const flat = {};
|
|
17220
|
+
Object.entries(item).forEach(([k, v]) => {
|
|
17221
|
+
if (v === null || typeof v !== 'object') flat[k] = v;
|
|
17222
|
+
});
|
|
17223
|
+
return flat
|
|
17224
|
+
})
|
|
17225
|
+
}
|
|
17226
|
+
return json
|
|
17227
|
+
} catch (err) {
|
|
17228
|
+
return errorMessageHandler(err, 'AAVE')
|
|
17229
|
+
}
|
|
17230
|
+
}
|
|
17566
17231
|
|
|
17567
17232
|
const dateStringToTimestamp = (val) => {
|
|
17568
17233
|
const [dd, mm, yyyy] = val.split('/');
|
|
@@ -17583,6 +17248,440 @@ const dateOrTimestamp = preprocessType(
|
|
|
17583
17248
|
numberType({ invalid_type_error: 'Date must be a valid DD/MM/YYYY or timestamp' }).int('Date must be an integer timestamp').nonnegative('Date must be a nonnegative timestamp').refine((n) => !isNaN(n), { message: 'Invalid date format or value: expected DD/MM/YYYY' })
|
|
17584
17249
|
);
|
|
17585
17250
|
|
|
17251
|
+
const baseSchema = objectType({
|
|
17252
|
+
addresses: stringType().nonempty(),
|
|
17253
|
+
category: enumType(['balance','txns']),
|
|
17254
|
+
chains: preprocessType(
|
|
17255
|
+
(val) => typeof val === 'string'
|
|
17256
|
+
? val.split(',').map(s => s.trim()).filter(Boolean)
|
|
17257
|
+
: val,
|
|
17258
|
+
arrayType(
|
|
17259
|
+
enumType(['ethereum','gnosis','base'])
|
|
17260
|
+
).nonempty()
|
|
17261
|
+
),
|
|
17262
|
+
startTime: dateOrTimestamp.optional(),
|
|
17263
|
+
endTime: dateOrTimestamp.optional(),
|
|
17264
|
+
page: numberType().int().nonnegative().default(1),
|
|
17265
|
+
offset: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"offset" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17266
|
+
});
|
|
17267
|
+
|
|
17268
|
+
const eoaParamsSchema = preprocessType(
|
|
17269
|
+
(val) => {
|
|
17270
|
+
const obj = { ...(val || {}) };
|
|
17271
|
+
// if balance, ignore startTime/endTime
|
|
17272
|
+
if (obj.category === 'balance') {
|
|
17273
|
+
delete obj.startTime;
|
|
17274
|
+
delete obj.endTime;
|
|
17275
|
+
}
|
|
17276
|
+
return obj
|
|
17277
|
+
},
|
|
17278
|
+
baseSchema.refine(data => {
|
|
17279
|
+
// for txns, startTime and endTime are required
|
|
17280
|
+
if (data.category === 'txns') {
|
|
17281
|
+
return data.startTime !== undefined && data.endTime !== undefined
|
|
17282
|
+
}
|
|
17283
|
+
return true
|
|
17284
|
+
}, {
|
|
17285
|
+
message: 'startTime and endTime required for txns',
|
|
17286
|
+
path: ['startTime'],
|
|
17287
|
+
})
|
|
17288
|
+
);
|
|
17289
|
+
|
|
17290
|
+
const isAddress = (input) => {
|
|
17291
|
+
return (/^0x[a-fA-F0-9]{40}$/.test(input))
|
|
17292
|
+
};
|
|
17293
|
+
|
|
17294
|
+
var isAddress$1 = {
|
|
17295
|
+
isAddress
|
|
17296
|
+
};
|
|
17297
|
+
|
|
17298
|
+
/* global document */
|
|
17299
|
+
/* global window */
|
|
17300
|
+
/* global ethers */
|
|
17301
|
+
|
|
17302
|
+
|
|
17303
|
+
|
|
17304
|
+
async function fromEnsNameToAddress(name) {
|
|
17305
|
+
if (typeof ethers === 'undefined') {
|
|
17306
|
+
await new Promise((resolve, reject) => {
|
|
17307
|
+
const script = document.createElement('script');
|
|
17308
|
+
script.src = 'https://cdn.jsdelivr.net/npm/ethers@6.10.0/dist/ethers.umd.min.js';
|
|
17309
|
+
script.onload = resolve;
|
|
17310
|
+
script.onerror = reject;
|
|
17311
|
+
document.head.appendChild(script);
|
|
17312
|
+
});
|
|
17313
|
+
}
|
|
17314
|
+
|
|
17315
|
+
const ALCHEMY_KEY = window.localStorage.getItem(UTILITY.ALCHEMY_API_KEY);
|
|
17316
|
+
if (!ALCHEMY_KEY) {
|
|
17317
|
+
console.error('alchemy api key missing');
|
|
17318
|
+
return null
|
|
17319
|
+
}
|
|
17320
|
+
const provider = new ethers.AlchemyProvider('mainnet', ALCHEMY_KEY);
|
|
17321
|
+
|
|
17322
|
+
try {
|
|
17323
|
+
const resolved = await provider.resolveName(name); // ENS ➝ address
|
|
17324
|
+
return resolved || null
|
|
17325
|
+
} catch (err) {
|
|
17326
|
+
console.error('ENS resolution failed:', err.message);
|
|
17327
|
+
return null
|
|
17328
|
+
}
|
|
17329
|
+
}
|
|
17330
|
+
const validateAndGetAddress = async (address) => {
|
|
17331
|
+
if(isAddress$1.isAddress(address)) return address
|
|
17332
|
+
|
|
17333
|
+
const resolvedAddress = await fromEnsNameToAddress(address);
|
|
17334
|
+
if(resolvedAddress) return resolvedAddress
|
|
17335
|
+
throw new ValidationError("Invalid address")
|
|
17336
|
+
};
|
|
17337
|
+
|
|
17338
|
+
var fromEnsNameToAddress$1 = {
|
|
17339
|
+
validateAndGetAddress
|
|
17340
|
+
};
|
|
17341
|
+
|
|
17342
|
+
let PROXY_MAP;
|
|
17343
|
+
|
|
17344
|
+
function initializeProxyMap() {
|
|
17345
|
+
if (!PROXY_MAP) {
|
|
17346
|
+
const fileverseProxyUrl = `${window.NEXT_PUBLIC_PROXY_BASE_URL}/proxy`;
|
|
17347
|
+
|
|
17348
|
+
PROXY_MAP = {
|
|
17349
|
+
Etherscan: {
|
|
17350
|
+
url: fileverseProxyUrl,
|
|
17351
|
+
removeParams: ['apikey']
|
|
17352
|
+
},
|
|
17353
|
+
Basescan: {
|
|
17354
|
+
url: fileverseProxyUrl,
|
|
17355
|
+
removeParams: ['apikey']
|
|
17356
|
+
},
|
|
17357
|
+
Gnosisscan: {
|
|
17358
|
+
url: fileverseProxyUrl,
|
|
17359
|
+
removeParams: ['apikey']
|
|
17360
|
+
},
|
|
17361
|
+
Coingecko: {
|
|
17362
|
+
url: fileverseProxyUrl,
|
|
17363
|
+
removeParams: ['apikey']
|
|
17364
|
+
},
|
|
17365
|
+
Firefly: {
|
|
17366
|
+
url: fileverseProxyUrl,
|
|
17367
|
+
removeParams: ['apikey']
|
|
17368
|
+
},
|
|
17369
|
+
Neynar: {
|
|
17370
|
+
url: fileverseProxyUrl,
|
|
17371
|
+
removeParams: ['api_key']
|
|
17372
|
+
},
|
|
17373
|
+
Safe: {
|
|
17374
|
+
url: fileverseProxyUrl,
|
|
17375
|
+
removeParams: ['api_key']
|
|
17376
|
+
},
|
|
17377
|
+
Defillama: {
|
|
17378
|
+
url: fileverseProxyUrl,
|
|
17379
|
+
removeParams: ['api_key']
|
|
17380
|
+
},
|
|
17381
|
+
GnosisPay: {
|
|
17382
|
+
url: fileverseProxyUrl,
|
|
17383
|
+
removeParams: ['api_key']
|
|
17384
|
+
},
|
|
17385
|
+
// Add more services as needed. It can be direct url instead of ENV variable
|
|
17386
|
+
// ANOTHER_SERVICE: "https://another-proxy-url.com"
|
|
17387
|
+
};
|
|
17388
|
+
}
|
|
17389
|
+
return PROXY_MAP;
|
|
17390
|
+
}
|
|
17391
|
+
|
|
17392
|
+
/**
|
|
17393
|
+
* Removes specified parameters from a URL
|
|
17394
|
+
* @param {string} url - The original URL
|
|
17395
|
+
* @param {string[]} paramsToRemove - Array of parameter names to remove
|
|
17396
|
+
* @returns {string} URL with specified parameters removed
|
|
17397
|
+
*/
|
|
17398
|
+
function removeUrlParams(url, paramsToRemove) {
|
|
17399
|
+
if (!paramsToRemove || paramsToRemove.length === 0) {
|
|
17400
|
+
return url;
|
|
17401
|
+
}
|
|
17402
|
+
|
|
17403
|
+
const urlObj = new URL(url);
|
|
17404
|
+
|
|
17405
|
+
paramsToRemove.forEach(param => {
|
|
17406
|
+
if (urlObj.searchParams.has(param)) {
|
|
17407
|
+
urlObj.searchParams.delete(param);
|
|
17408
|
+
}
|
|
17409
|
+
});
|
|
17410
|
+
|
|
17411
|
+
return urlObj.toString();
|
|
17412
|
+
}
|
|
17413
|
+
|
|
17414
|
+
/**
|
|
17415
|
+
* Handles URL routing through proxy or direct API calls
|
|
17416
|
+
* @param {string} url - The original API URL
|
|
17417
|
+
* @param {string} serviceName - [OPTIONAL] The name of the service (e.g., 'EOA')
|
|
17418
|
+
* @param {object} headers - [OPTIONAL] The name of the service (e.g., 'EOA')
|
|
17419
|
+
* @returns {Object} Object containing URL and HEADERS for the fetch request
|
|
17420
|
+
*/
|
|
17421
|
+
function getUrlAndHeaders({ url, serviceName, headers = {} }) {
|
|
17422
|
+
const proxyMap = initializeProxyMap();
|
|
17423
|
+
// Check if proxy is enabled in localStorage
|
|
17424
|
+
const apiKeyLS = window.localStorage.getItem(SERVICES_API_KEY[serviceName]);
|
|
17425
|
+
const isProxyModeEnabledValue = apiKeyLS === 'DEFAULT_PROXY_MODE';
|
|
17426
|
+
|
|
17427
|
+
// Check if proxy URL exists for this service
|
|
17428
|
+
const proxyConfig = proxyMap[serviceName];
|
|
17429
|
+
|
|
17430
|
+
if (!proxyConfig && SERVICES_API_KEY[serviceName] && (!apiKeyLS || apiKeyLS === '')) {
|
|
17431
|
+
throw new MissingApiKeyError(SERVICES_API_KEY[serviceName])
|
|
17432
|
+
}
|
|
17433
|
+
|
|
17434
|
+
// If proxy mode is enabled AND proxy URL exists for this service
|
|
17435
|
+
if ((isProxyModeEnabledValue || !apiKeyLS || apiKeyLS === '') && proxyConfig) {
|
|
17436
|
+
// Remove specified parameters from the target URL
|
|
17437
|
+
const cleanedUrl = removeUrlParams(url, proxyConfig.removeParams);
|
|
17438
|
+
|
|
17439
|
+
return {
|
|
17440
|
+
URL: proxyConfig.url,
|
|
17441
|
+
HEADERS: {
|
|
17442
|
+
'target-url': cleanedUrl,
|
|
17443
|
+
method: 'GET',
|
|
17444
|
+
'Content-Type': 'application/json'
|
|
17445
|
+
}
|
|
17446
|
+
};
|
|
17447
|
+
}
|
|
17448
|
+
|
|
17449
|
+
return {
|
|
17450
|
+
URL: url,
|
|
17451
|
+
HEADERS: {
|
|
17452
|
+
...headers,
|
|
17453
|
+
}
|
|
17454
|
+
};
|
|
17455
|
+
}
|
|
17456
|
+
|
|
17457
|
+
const fromTimeStampToBlock = async (timestamp, chain, apiKey) => {
|
|
17458
|
+
if (!timestamp || !chain) return
|
|
17459
|
+
const chainId = CHAIN_ID_MAP[chain];
|
|
17460
|
+
const url = `https://api.etherscan.io/v2/api?module=block&action=getblocknobytime×tamp=${timestamp}&closest=before&apikey=${apiKey}&chainId=${chainId}`;
|
|
17461
|
+
const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url, serviceName: 'Etherscan', headers: {} });
|
|
17462
|
+
const res = await fetch(finalUrl, {
|
|
17463
|
+
method: 'GET',
|
|
17464
|
+
headers: HEADERS,
|
|
17465
|
+
});
|
|
17466
|
+
const json = await res.json();
|
|
17467
|
+
return parseInt(json.result);
|
|
17468
|
+
|
|
17469
|
+
};
|
|
17470
|
+
|
|
17471
|
+
var fromTimestampToBlock = {
|
|
17472
|
+
fromTimeStampToBlock
|
|
17473
|
+
};
|
|
17474
|
+
|
|
17475
|
+
function toTimestamp(dateStr) {
|
|
17476
|
+
// Expecting format: "DD/MM/YYYY"
|
|
17477
|
+
const [day, month, year] = dateStr.split("/").map(Number);
|
|
17478
|
+
const date = new Date(year, month - 1, day);
|
|
17479
|
+
return Math.floor(date.getTime() / 1000); // Unix timestamp in seconds
|
|
17480
|
+
}
|
|
17481
|
+
|
|
17482
|
+
/* global window */
|
|
17483
|
+
|
|
17484
|
+
|
|
17485
|
+
|
|
17486
|
+
async function EOA() {
|
|
17487
|
+
try {
|
|
17488
|
+
const [addresses, category, chains, startTime, endTime, page = 1, offset = 10] =
|
|
17489
|
+
argsToArray(arguments);
|
|
17490
|
+
validateParams(eoaParamsSchema, { addresses, category, chains, startTime, endTime, page, offset });
|
|
17491
|
+
|
|
17492
|
+
const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Etherscan);
|
|
17493
|
+
|
|
17494
|
+
const INPUTS = addresses.split(',').map(s => s.trim()).filter(Boolean);
|
|
17495
|
+
const CHAINS = chains.split(',').map(s => s.trim()).filter(Boolean);
|
|
17496
|
+
|
|
17497
|
+
const ADDRESS_MAP = {};
|
|
17498
|
+
for (const inp of INPUTS) {
|
|
17499
|
+
if (isAddress$1.isAddress(inp)) {
|
|
17500
|
+
ADDRESS_MAP[inp.toLowerCase()] = null;
|
|
17501
|
+
} else {
|
|
17502
|
+
const _address = await fromEnsNameToAddress$1.validateAndGetAddress(inp);
|
|
17503
|
+
ADDRESS_MAP[_address.toLowerCase()] = _address;
|
|
17504
|
+
}
|
|
17505
|
+
}
|
|
17506
|
+
const ADDRS = Object.keys(ADDRESS_MAP);
|
|
17507
|
+
const out = [];
|
|
17508
|
+
|
|
17509
|
+
async function fetchJSON(url) {
|
|
17510
|
+
const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url, serviceName: 'Etherscan', headers: {} });
|
|
17511
|
+
const res = await fetch(finalUrl, {
|
|
17512
|
+
method: 'GET',
|
|
17513
|
+
headers: HEADERS,
|
|
17514
|
+
});
|
|
17515
|
+
if (!res.ok) throw new NetworkError(SERVICES_API_KEY.Etherscan, res.status)
|
|
17516
|
+
const json = await res.json();
|
|
17517
|
+
|
|
17518
|
+
if (typeof json.result === 'string') {
|
|
17519
|
+
if (json.result.includes('Invalid API Key')) throw new InvalidApiKeyError(SERVICES_API_KEY.Etherscan)
|
|
17520
|
+
if (json.result.includes('Max rate limit reached')) throw new RateLimitError(SERVICES_API_KEY.Etherscan)
|
|
17521
|
+
}
|
|
17522
|
+
return json.result
|
|
17523
|
+
}
|
|
17524
|
+
|
|
17525
|
+
|
|
17526
|
+
for (const chain of CHAINS) {
|
|
17527
|
+
const chainId = CHAIN_ID_MAP[chain];
|
|
17528
|
+
if (!chainId) throw new ValidationError(`Invalid chain: ${chain}`)
|
|
17529
|
+
|
|
17530
|
+
if (category === 'balance') {
|
|
17531
|
+
// chunk 20
|
|
17532
|
+
for (let i = 0; i < ADDRS.length; i += 20) {
|
|
17533
|
+
const slice = ADDRS.slice(i, i + 20).join(',');
|
|
17534
|
+
const url =
|
|
17535
|
+
`https://api.etherscan.io/v2/api?chainid=${chainId}` +
|
|
17536
|
+
`&module=account&action=addresstokenbalance&address=${slice}` +
|
|
17537
|
+
`&page=${page}&offset=${offset}&apikey=${apiKey}`;
|
|
17538
|
+
const data = await fetchJSON(url);
|
|
17539
|
+
if (!Array.isArray(data)) return data
|
|
17540
|
+
data.forEach((item, idx) => out.push({ chain, address: ADDRS[i + idx], name: ADDRESS_MAP[ADDRS[i + idx]], ...item }));
|
|
17541
|
+
}
|
|
17542
|
+
} else {
|
|
17543
|
+
// txns
|
|
17544
|
+
const sb = await fromTimestampToBlock.fromTimeStampToBlock(toTimestamp(startTime), chain, apiKey);
|
|
17545
|
+
const eb = await fromTimestampToBlock.fromTimeStampToBlock(toTimestamp(endTime), chain, apiKey);
|
|
17546
|
+
if (!sb) throw new ValidationError(`Invalid startTime: ${startTime}`)
|
|
17547
|
+
if (!eb) throw new ValidationError(`Invalid endTime: ${endTime}`)
|
|
17548
|
+
for (const addr of ADDRS) {
|
|
17549
|
+
const url =
|
|
17550
|
+
`https://api.etherscan.io/v2/api?chainid=${chainId}` +
|
|
17551
|
+
`&module=account&action=tokentx&address=${addr}` +
|
|
17552
|
+
`&startblock=${sb}&endblock=${eb}` +
|
|
17553
|
+
`&page=${page}&offset=${offset}&sort=asc&apikey=${apiKey}`;
|
|
17554
|
+
const data = await fetchJSON(url);
|
|
17555
|
+
if (!Array.isArray(data)) return data
|
|
17556
|
+
data.forEach(item => out.push({ chain, address: addr, name: ADDRESS_MAP[addr], ...item }));
|
|
17557
|
+
}
|
|
17558
|
+
}
|
|
17559
|
+
}
|
|
17560
|
+
return out
|
|
17561
|
+
} catch (err) {
|
|
17562
|
+
return errorMessageHandler(err, 'EOA')
|
|
17563
|
+
}
|
|
17564
|
+
}
|
|
17565
|
+
|
|
17566
|
+
const gasSchema$1 = objectType({
|
|
17567
|
+
type: literalType('gas'),
|
|
17568
|
+
startDate: dateOrTimestamp.optional(),
|
|
17569
|
+
endDate: dateOrTimestamp.optional(),
|
|
17570
|
+
page: numberType().int().nonnegative().default(1),
|
|
17571
|
+
limit: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"limit" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17572
|
+
});
|
|
17573
|
+
|
|
17574
|
+
const txnSchema$1 = objectType({
|
|
17575
|
+
type: enumType(['all-txns', 'token-txns', 'nft-txns']),
|
|
17576
|
+
address: stringType().nonempty(),
|
|
17577
|
+
startDate: dateOrTimestamp.optional(),
|
|
17578
|
+
endDate: dateOrTimestamp.optional(),
|
|
17579
|
+
page: numberType().int().nonnegative().default(1),
|
|
17580
|
+
limit: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"limit" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17581
|
+
});
|
|
17582
|
+
|
|
17583
|
+
const baseParamsSchema = discriminatedUnionType('type', [gasSchema$1, txnSchema$1]);
|
|
17584
|
+
|
|
17585
|
+
async function handleScanRequest({
|
|
17586
|
+
type,
|
|
17587
|
+
address,
|
|
17588
|
+
startDate,
|
|
17589
|
+
endDate,
|
|
17590
|
+
page = 1,
|
|
17591
|
+
offset = 10,
|
|
17592
|
+
apiKey,
|
|
17593
|
+
functionName,
|
|
17594
|
+
chainId,
|
|
17595
|
+
network
|
|
17596
|
+
}) {
|
|
17597
|
+
const API_INFO_MAP = {
|
|
17598
|
+
BASE: { url: 'https://api.basescan.org/api', apiKeyName: SERVICES_API_KEY.Basescan },
|
|
17599
|
+
ETHERSCAN: { url: 'https://api.etherscan.io/v2/api', apiKeyName: SERVICES_API_KEY.Etherscan },
|
|
17600
|
+
GNOSIS: { url: 'https://api.gnosisscan.io/api', apiKeyName: SERVICES_API_KEY.Gnosisscan }
|
|
17601
|
+
};
|
|
17602
|
+
|
|
17603
|
+
if (type !== 'gas') {
|
|
17604
|
+
address = await fromEnsNameToAddress$1.validateAndGetAddress(address);
|
|
17605
|
+
}
|
|
17606
|
+
|
|
17607
|
+
const apiInfo = API_INFO_MAP[functionName];
|
|
17608
|
+
const baseUrl = apiInfo?.url;
|
|
17609
|
+
if (!baseUrl) throw new ValidationError(`Api not found for: ${functionName}`)
|
|
17610
|
+
|
|
17611
|
+
|
|
17612
|
+
const ACTION_MAP = {
|
|
17613
|
+
'all-txns': 'txlist',
|
|
17614
|
+
'token-txns': 'tokentx',
|
|
17615
|
+
'nft-txns': 'tokennfttx',
|
|
17616
|
+
'gas': 'gasoracle'
|
|
17617
|
+
};
|
|
17618
|
+
|
|
17619
|
+
const action = ACTION_MAP[type];
|
|
17620
|
+
if (!action) throw new ValidationError(`Invalid type: ${type}`)
|
|
17621
|
+
|
|
17622
|
+
const module = action === 'gasoracle' ? 'gastracker' : 'account';
|
|
17623
|
+
let url = `${baseUrl}?chainid=${chainId}&module=${module}&action=${action}&apikey=${apiKey}`;
|
|
17624
|
+
|
|
17625
|
+
if (['all-txns', 'token-txns', 'nft-txns'].includes(type)) {
|
|
17626
|
+
url += `&address=${address}&startblock=0&endblock=99999999&sort=asc`;
|
|
17627
|
+
|
|
17628
|
+
if (!isNaN(startDate) && !isNaN(endDate)) {
|
|
17629
|
+
const [startBlock, endBlock] = await Promise.all([
|
|
17630
|
+
fromTimestampToBlock.fromTimeStampToBlock(toTimestamp(startDate), network, apiKey),
|
|
17631
|
+
fromTimestampToBlock.fromTimeStampToBlock(toTimestamp(endDate), network, apiKey)
|
|
17632
|
+
]);
|
|
17633
|
+
url += `&startblock=${startBlock || '0'}&endblock=${endBlock || '99999999'}`;
|
|
17634
|
+
}
|
|
17635
|
+
url += `&page=${page}&offset=${offset}`;
|
|
17636
|
+
}
|
|
17637
|
+
const { URL: finalUrl, HEADERS } = getUrlAndHeaders({url, serviceName: apiInfo.apiKeyName, headers: {}});
|
|
17638
|
+
const res = await fetch(finalUrl, {
|
|
17639
|
+
method: 'GET',
|
|
17640
|
+
headers: HEADERS,
|
|
17641
|
+
});
|
|
17642
|
+
if (!res.ok) {
|
|
17643
|
+
throw new NetworkError(apiInfo.apiKeyName, res.status)
|
|
17644
|
+
}
|
|
17645
|
+
const json = await res.json();
|
|
17646
|
+
|
|
17647
|
+
if (typeof json.result === 'string') {
|
|
17648
|
+
if (json.result.includes('Invalid API Key')){
|
|
17649
|
+
throw new InvalidApiKeyError(apiInfo.apiKeyName)
|
|
17650
|
+
}
|
|
17651
|
+
|
|
17652
|
+
if (json.result.includes('Max rate limit reached'))
|
|
17653
|
+
throw new RateLimitError(apiInfo.apiKeyName)
|
|
17654
|
+
}
|
|
17655
|
+
|
|
17656
|
+
return type === 'gas' && !Array.isArray(json.result) ? [json.result] : json.result
|
|
17657
|
+
}
|
|
17658
|
+
|
|
17659
|
+
/* global window */
|
|
17660
|
+
|
|
17661
|
+
|
|
17662
|
+
async function BASE() {
|
|
17663
|
+
try {
|
|
17664
|
+
const [type, address, startDate, endDate, page, limit] = argsToArray(arguments);
|
|
17665
|
+
validateParams(baseParamsSchema, { type, address, startDate, endDate, page, limit });
|
|
17666
|
+
const API_KEY = window.localStorage.getItem(SERVICES_API_KEY.Basescan);
|
|
17667
|
+
|
|
17668
|
+
return await handleScanRequest({
|
|
17669
|
+
type,
|
|
17670
|
+
address,
|
|
17671
|
+
startDate,
|
|
17672
|
+
endDate,
|
|
17673
|
+
page,
|
|
17674
|
+
offset: limit,
|
|
17675
|
+
apiKey: API_KEY,
|
|
17676
|
+
functionName: 'BASE',
|
|
17677
|
+
chainId: CHAIN_ID_MAP.base,
|
|
17678
|
+
network: 'base'
|
|
17679
|
+
})
|
|
17680
|
+
} catch (error) {
|
|
17681
|
+
return errorMessageHandler(error, 'BASE')
|
|
17682
|
+
}
|
|
17683
|
+
}
|
|
17684
|
+
|
|
17586
17685
|
const blockscoutParamsSchema = objectType({
|
|
17587
17686
|
address: stringType().nonempty(),
|
|
17588
17687
|
type: enumType(['stat', 'txns', 'tokens']),
|
|
@@ -17593,44 +17692,78 @@ const blockscoutParamsSchema = objectType({
|
|
|
17593
17692
|
offset: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"offset" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17594
17693
|
});
|
|
17595
17694
|
|
|
17596
|
-
|
|
17597
|
-
|
|
17598
|
-
|
|
17599
|
-
|
|
17600
|
-
|
|
17601
|
-
|
|
17602
|
-
|
|
17695
|
+
async function BLOCKSCOUT() {
|
|
17696
|
+
try {
|
|
17697
|
+
const [
|
|
17698
|
+
address,
|
|
17699
|
+
type,
|
|
17700
|
+
chain = 'ethereum',
|
|
17701
|
+
startTimestamp,
|
|
17702
|
+
endTimestamp,
|
|
17703
|
+
page,
|
|
17704
|
+
offset,
|
|
17705
|
+
] = argsToArray(arguments);
|
|
17603
17706
|
|
|
17604
|
-
|
|
17605
|
-
|
|
17606
|
-
|
|
17607
|
-
|
|
17608
|
-
|
|
17609
|
-
|
|
17610
|
-
|
|
17611
|
-
|
|
17707
|
+
validateParams(blockscoutParamsSchema, {
|
|
17708
|
+
address,
|
|
17709
|
+
type,
|
|
17710
|
+
chain,
|
|
17711
|
+
startTimestamp,
|
|
17712
|
+
endTimestamp,
|
|
17713
|
+
page,
|
|
17714
|
+
offset
|
|
17715
|
+
});
|
|
17612
17716
|
|
|
17613
|
-
const
|
|
17717
|
+
const startTs =
|
|
17718
|
+
startTimestamp ?? Math.floor((Date.now() - 30 * 24 * 3600 * 1000) / 1000);
|
|
17719
|
+
const endTs = endTimestamp;
|
|
17614
17720
|
|
|
17615
|
-
const
|
|
17616
|
-
type: literalType('gas'),
|
|
17617
|
-
startDate: dateOrTimestamp.optional(),
|
|
17618
|
-
endDate: dateOrTimestamp.optional(),
|
|
17619
|
-
page: numberType().int().nonnegative().default(1),
|
|
17620
|
-
limit: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"limit" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17621
|
-
});
|
|
17721
|
+
const resolvedAddress = await fromEnsNameToAddress$1.validateAndGetAddress(address);
|
|
17622
17722
|
|
|
17623
|
-
const
|
|
17624
|
-
type: enumType(['all-txns', 'token-txns', 'nft-txns']),
|
|
17625
|
-
address: stringType().nonempty(),
|
|
17626
|
-
startDate: dateOrTimestamp.optional(),
|
|
17627
|
-
endDate: dateOrTimestamp.optional(),
|
|
17628
|
-
chain: enumType(['ethereum','base','gnosis']),
|
|
17629
|
-
page: numberType().int().nonnegative().default(1),
|
|
17630
|
-
limit: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"limit" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17631
|
-
});
|
|
17723
|
+
const hostname = BLOCKSCOUT_CHAINS_MAP[chain];
|
|
17632
17724
|
|
|
17633
|
-
|
|
17725
|
+
let requestUrl;
|
|
17726
|
+
switch (type) {
|
|
17727
|
+
case 'stat':
|
|
17728
|
+
requestUrl = `${hostname}/api/v2/addresses/${resolvedAddress}/counters`;
|
|
17729
|
+
break
|
|
17730
|
+
case 'txns':
|
|
17731
|
+
requestUrl =
|
|
17732
|
+
`${hostname}/api?module=account&action=txlist` +
|
|
17733
|
+
`&address=${resolvedAddress}` +
|
|
17734
|
+
`&start_timestamp=${startTs}` +
|
|
17735
|
+
`&end_timestamp=${endTs ?? ''}` +
|
|
17736
|
+
`&page=${page}` +
|
|
17737
|
+
`&offset=${offset}` +
|
|
17738
|
+
`&sort=asc`;
|
|
17739
|
+
break
|
|
17740
|
+
case 'tokens':
|
|
17741
|
+
requestUrl =
|
|
17742
|
+
`${hostname}/api?module=account&action=tokenlist` +
|
|
17743
|
+
`&address=${resolvedAddress}`;
|
|
17744
|
+
break
|
|
17745
|
+
}
|
|
17746
|
+
|
|
17747
|
+
const response = await fetch(requestUrl);
|
|
17748
|
+
if (!response.ok) {
|
|
17749
|
+
throw new NetworkError('BLOCKSCOUT', response.status)
|
|
17750
|
+
}
|
|
17751
|
+
|
|
17752
|
+
const json = await response.json();
|
|
17753
|
+
|
|
17754
|
+
// custom error conditions
|
|
17755
|
+
if (json?.result?.includes('Invalid parameter(s)')) {
|
|
17756
|
+
throw new ValidationError('Invalid parameters')
|
|
17757
|
+
}
|
|
17758
|
+
if (json?.result?.includes('Not found')) {
|
|
17759
|
+
throw new ValidationError('Address information not found')
|
|
17760
|
+
}
|
|
17761
|
+
|
|
17762
|
+
return type === 'stat' ? [json] : json.result
|
|
17763
|
+
} catch (err) {
|
|
17764
|
+
return errorMessageHandler(err, 'BLOCKSCOUT')
|
|
17765
|
+
}
|
|
17766
|
+
}
|
|
17634
17767
|
|
|
17635
17768
|
const allowedValues = ['1h', '24h', '7d'];
|
|
17636
17769
|
const param2Schema = stringType()
|
|
@@ -17671,123 +17804,67 @@ const coingeckoParamsSchema = discriminatedUnionType('category', [
|
|
|
17671
17804
|
derivativesSchema,
|
|
17672
17805
|
]);
|
|
17673
17806
|
|
|
17674
|
-
const baseSchema = objectType({
|
|
17675
|
-
addresses: stringType().nonempty(),
|
|
17676
|
-
category: enumType(['balance','txns']),
|
|
17677
|
-
chains: preprocessType(
|
|
17678
|
-
(val) => typeof val === 'string'
|
|
17679
|
-
? val.split(',').map(s => s.trim()).filter(Boolean)
|
|
17680
|
-
: val,
|
|
17681
|
-
arrayType(
|
|
17682
|
-
enumType(['ethereum','gnosis','base'])
|
|
17683
|
-
).nonempty()
|
|
17684
|
-
),
|
|
17685
|
-
startTime: dateOrTimestamp.optional(),
|
|
17686
|
-
endTime: dateOrTimestamp.optional(),
|
|
17687
|
-
page: numberType().int().nonnegative().default(1),
|
|
17688
|
-
offset: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"offset" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17689
|
-
});
|
|
17690
|
-
|
|
17691
|
-
const eoaParamsSchema = preprocessType(
|
|
17692
|
-
(val) => {
|
|
17693
|
-
const obj = { ...(val || {}) };
|
|
17694
|
-
// if balance, ignore startTime/endTime
|
|
17695
|
-
if (obj.category === 'balance') {
|
|
17696
|
-
delete obj.startTime;
|
|
17697
|
-
delete obj.endTime;
|
|
17698
|
-
}
|
|
17699
|
-
return obj
|
|
17700
|
-
},
|
|
17701
|
-
baseSchema.refine(data => {
|
|
17702
|
-
// for txns, startTime and endTime are required
|
|
17703
|
-
if (data.category === 'txns') {
|
|
17704
|
-
return data.startTime !== undefined && data.endTime !== undefined
|
|
17705
|
-
}
|
|
17706
|
-
return true
|
|
17707
|
-
}, {
|
|
17708
|
-
message: 'startTime and endTime required for txns',
|
|
17709
|
-
path: ['startTime'],
|
|
17710
|
-
})
|
|
17711
|
-
);
|
|
17712
|
-
|
|
17713
|
-
const safeParamsSchema = objectType({
|
|
17714
|
-
address: stringType().nonempty(),
|
|
17715
|
-
utility: literalType('txns'),
|
|
17716
|
-
chain: enumType(['ethereum','gnosis']),
|
|
17717
|
-
limit: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"limit" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17718
|
-
offset: numberType().int().nonnegative().default(0),
|
|
17719
|
-
});
|
|
17720
|
-
|
|
17721
|
-
const categories = ['protocols','yields','dex','fees'];
|
|
17722
|
-
const defillamaParamsSchema = objectType({
|
|
17723
|
-
category: enumType(categories)
|
|
17724
|
-
});
|
|
17725
|
-
|
|
17726
|
-
const CATEGORY_URLS = {
|
|
17727
|
-
protocols: 'https://api.llama.fi/protocols',
|
|
17728
|
-
yields: 'https://yields.llama.fi/pools',
|
|
17729
|
-
dex: 'https://api.llama.fi/overview/dexs?excludeTotalDataChart=true&excludeTotalDataChartBreakdown=true',
|
|
17730
|
-
fees: 'https://api.llama.fi/overview/fees?excludeTotalDataChart=true&excludeTotalDataChartBreakdown=true&dataType=dailyFees'
|
|
17731
|
-
};
|
|
17732
|
-
|
|
17733
|
-
const uniswapParamsSchema = objectType({
|
|
17734
|
-
graphType: enumType(['v3','v3-raw']),
|
|
17735
|
-
category: enumType(['tokens','markets']),
|
|
17736
|
-
param1: stringType().nonempty(),
|
|
17737
|
-
param2: stringType().optional(),
|
|
17738
|
-
});
|
|
17739
|
-
|
|
17740
|
-
const aaveParamsSchema = objectType({
|
|
17741
|
-
graphType: enumType(['v2','v2-raw']),
|
|
17742
|
-
category: enumType(['tokens','markets']),
|
|
17743
|
-
param1: stringType().nonempty(),
|
|
17744
|
-
param2: stringType().optional(),
|
|
17745
|
-
});
|
|
17746
|
-
|
|
17747
17807
|
/* global window */
|
|
17748
17808
|
|
|
17749
17809
|
|
|
17750
17810
|
|
|
17751
|
-
async function
|
|
17811
|
+
async function COINGECKO() {
|
|
17752
17812
|
try {
|
|
17753
|
-
const [
|
|
17754
|
-
|
|
17755
|
-
validateParams(fireflyParamsSchema, {
|
|
17756
|
-
platform,
|
|
17757
|
-
contentType,
|
|
17758
|
-
identifier,
|
|
17759
|
-
start,
|
|
17760
|
-
end,
|
|
17761
|
-
});
|
|
17813
|
+
const [category, param1, param2] = argsToArray(arguments);
|
|
17814
|
+
validateParams(coingeckoParamsSchema, { category, param1, param2 });
|
|
17762
17815
|
|
|
17763
|
-
const apiKey = window.localStorage.getItem(SERVICES_API_KEY.
|
|
17816
|
+
const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Coingecko);
|
|
17764
17817
|
|
|
17765
|
-
const
|
|
17766
|
-
|
|
17767
|
-
|
|
17768
|
-
|
|
17769
|
-
|
|
17770
|
-
|
|
17771
|
-
|
|
17772
|
-
|
|
17773
|
-
|
|
17774
|
-
|
|
17775
|
-
|
|
17776
|
-
|
|
17818
|
+
const headers = {
|
|
17819
|
+
accept: 'application/json',
|
|
17820
|
+
'x-cg-demo-api-key': apiKey,
|
|
17821
|
+
};
|
|
17822
|
+
let url = '';
|
|
17823
|
+
switch (category?.toLowerCase?.()) {
|
|
17824
|
+
case 'price': {
|
|
17825
|
+
const vs = param2 || 'usd';
|
|
17826
|
+
url = `https://api.coingecko.com/api/v3/simple/price?vs_currencies=${vs}&symbols=${param1}`;
|
|
17827
|
+
break
|
|
17828
|
+
}
|
|
17829
|
+
case 'market': {
|
|
17830
|
+
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' };
|
|
17831
|
+
const _category = map[param1] || '';
|
|
17832
|
+
const trend = param2 ? `&price_change_percentage=${param2}` : '';
|
|
17833
|
+
url = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&include_tokens=top&page=1&per_page=100${_category ? `&category=${_category}` : ''}${trend}`;
|
|
17834
|
+
break
|
|
17835
|
+
}
|
|
17836
|
+
case 'stablecoins': {
|
|
17837
|
+
const _category = param1 === 'all' ? 'stablecoins' : param1;
|
|
17838
|
+
const trend = param2 ? `&price_change_percentage=${param2}` : '';
|
|
17839
|
+
url = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&category=${_category}&order=market_cap_desc&page=1&per_page=100${trend}`;
|
|
17840
|
+
break
|
|
17841
|
+
}
|
|
17842
|
+
case 'derivatives': {
|
|
17843
|
+
url = (!param1 || param1 === 'all')
|
|
17844
|
+
? 'https://api.coingecko.com/api/v3/derivatives'
|
|
17845
|
+
: `https://api.coingecko.com/api/v3/derivatives/exchanges/${param1}?include_tickers=all`;
|
|
17846
|
+
break
|
|
17847
|
+
}
|
|
17848
|
+
}
|
|
17849
|
+
const {URL: finalUrl, HEADERS} = getUrlAndHeaders({url, serviceName: 'Coingecko', headers});
|
|
17777
17850
|
|
|
17778
|
-
const
|
|
17779
|
-
const
|
|
17780
|
-
|
|
17781
|
-
|
|
17782
|
-
|
|
17783
|
-
|
|
17784
|
-
throw new NetworkError(SERVICES_API_KEY.Firefly, response.status)
|
|
17851
|
+
const res = await fetch(finalUrl, { headers: HEADERS });
|
|
17852
|
+
const json = await res.json();
|
|
17853
|
+
if (!res.ok) {
|
|
17854
|
+
const msg = json?.status?.error_message || '';
|
|
17855
|
+
if (msg.includes('API Key Missing')) throw new InvalidApiKeyError(SERVICES_API_KEY.Coingecko)
|
|
17856
|
+
throw new NetworkError(SERVICES_API_KEY.Coingecko, res.status)
|
|
17785
17857
|
}
|
|
17786
17858
|
|
|
17787
|
-
|
|
17788
|
-
|
|
17789
|
-
|
|
17859
|
+
if (category === 'price') {
|
|
17860
|
+
const out = {};
|
|
17861
|
+
for (const [token, prices] of Object.entries(json))
|
|
17862
|
+
for (const [cur, val] of Object.entries(prices))
|
|
17863
|
+
out[`${token.charAt(0).toUpperCase() + token.slice(1)}_${cur.toUpperCase()}`] = val;
|
|
17864
|
+
return [out]
|
|
17790
17865
|
}
|
|
17866
|
+
|
|
17867
|
+
const data = Array.isArray(json) ? json : [json];
|
|
17791
17868
|
return data.map(item => {
|
|
17792
17869
|
const flat = {};
|
|
17793
17870
|
for (const [key, value] of Object.entries(item)) {
|
|
@@ -17795,78 +17872,133 @@ async function FIREFLY() {
|
|
|
17795
17872
|
flat[key] = value;
|
|
17796
17873
|
}
|
|
17797
17874
|
}
|
|
17798
|
-
flat.platform = platform;
|
|
17799
17875
|
return flat
|
|
17800
17876
|
})
|
|
17801
|
-
|
|
17802
17877
|
} catch (err) {
|
|
17803
|
-
return errorMessageHandler(err, '
|
|
17878
|
+
return errorMessageHandler(err, 'COINGECKO')
|
|
17804
17879
|
}
|
|
17805
17880
|
}
|
|
17806
17881
|
|
|
17882
|
+
const categories = ['protocols','yields','dex','fees'];
|
|
17883
|
+
const defillamaParamsSchema = objectType({
|
|
17884
|
+
category: enumType(categories)
|
|
17885
|
+
});
|
|
17886
|
+
|
|
17887
|
+
const CATEGORY_URLS = {
|
|
17888
|
+
protocols: 'https://api.llama.fi/protocols',
|
|
17889
|
+
yields: 'https://yields.llama.fi/pools',
|
|
17890
|
+
dex: 'https://api.llama.fi/overview/dexs?excludeTotalDataChart=true&excludeTotalDataChartBreakdown=true',
|
|
17891
|
+
fees: 'https://api.llama.fi/overview/fees?excludeTotalDataChart=true&excludeTotalDataChartBreakdown=true&dataType=dailyFees'
|
|
17892
|
+
};
|
|
17807
17893
|
|
|
17808
|
-
async function
|
|
17894
|
+
async function DEFILLAMA() {
|
|
17809
17895
|
try {
|
|
17810
|
-
const [
|
|
17811
|
-
|
|
17896
|
+
const [category] = argsToArray(arguments);
|
|
17897
|
+
validateParams(defillamaParamsSchema, { category });
|
|
17898
|
+
const url = CATEGORY_URLS[category];
|
|
17899
|
+
if (!url) throw new ValidationError(`Invalid category: ${category}`)
|
|
17900
|
+
const res = await fetch(url);
|
|
17901
|
+
if (!res.ok) throw new NetworkError(SERVICES_API_KEY.Defillama, res.status)
|
|
17902
|
+
let json = await res.json();
|
|
17812
17903
|
|
|
17813
|
-
|
|
17814
|
-
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
|
|
17818
|
-
|
|
17904
|
+
switch (category) {
|
|
17905
|
+
case 'protocols':
|
|
17906
|
+
json = Array.isArray(json) ? json.slice(0, 500) : [];
|
|
17907
|
+
break
|
|
17908
|
+
case 'yields':
|
|
17909
|
+
json = Array.isArray(json.data) ? json.data.slice(0, 500) : [];
|
|
17910
|
+
break
|
|
17911
|
+
case 'dex':
|
|
17912
|
+
case 'fees':
|
|
17913
|
+
json = Array.isArray(json.protocols) ? json.protocols.slice(0, 500) : [];
|
|
17914
|
+
break
|
|
17915
|
+
}
|
|
17819
17916
|
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
17917
|
+
return (Array.isArray(json) ? json : [json]).map(item => {
|
|
17918
|
+
const out = {};
|
|
17919
|
+
for (const [k, v] of Object.entries(item)) {
|
|
17920
|
+
if (v === null || typeof v !== 'object') out[k] = v;
|
|
17921
|
+
}
|
|
17922
|
+
return out
|
|
17923
|
+
})
|
|
17924
|
+
} catch (err) {
|
|
17925
|
+
return errorMessageHandler(err, 'DEFILLAMA')
|
|
17926
|
+
}
|
|
17927
|
+
}
|
|
17823
17928
|
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
|
|
17829
|
-
|
|
17830
|
-
|
|
17831
|
-
.map((s) => s.trim())
|
|
17832
|
-
.filter(Boolean)
|
|
17833
|
-
.join(',')
|
|
17834
|
-
);
|
|
17835
|
-
const typeMap = {
|
|
17836
|
-
posts: 'lensid',
|
|
17837
|
-
replies: 'lenspostid',
|
|
17838
|
-
};
|
|
17839
|
-
url.searchParams.set('type', typeMap[contentType]);
|
|
17840
|
-
url.searchParams.set('start', String(start));
|
|
17841
|
-
url.searchParams.set('end', String(end));
|
|
17929
|
+
const gasSchema = objectType({
|
|
17930
|
+
type: literalType('gas'),
|
|
17931
|
+
startDate: dateOrTimestamp.optional(),
|
|
17932
|
+
endDate: dateOrTimestamp.optional(),
|
|
17933
|
+
page: numberType().int().nonnegative().default(1),
|
|
17934
|
+
limit: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"limit" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17935
|
+
});
|
|
17842
17936
|
|
|
17843
|
-
|
|
17937
|
+
const txnSchema = objectType({
|
|
17938
|
+
type: enumType(['all-txns', 'token-txns', 'nft-txns']),
|
|
17939
|
+
address: stringType().nonempty(),
|
|
17940
|
+
startDate: dateOrTimestamp.optional(),
|
|
17941
|
+
endDate: dateOrTimestamp.optional(),
|
|
17942
|
+
chain: enumType(['ethereum','base','gnosis']),
|
|
17943
|
+
page: numberType().int().nonnegative().default(1),
|
|
17944
|
+
limit: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"limit" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17945
|
+
});
|
|
17844
17946
|
|
|
17845
|
-
|
|
17846
|
-
method: 'GET',
|
|
17847
|
-
headers: HEADERS,
|
|
17848
|
-
});
|
|
17849
|
-
if (!response.ok) {
|
|
17850
|
-
throw new NetworkError(SERVICES_API_KEY.Firefly, response.status)
|
|
17851
|
-
}
|
|
17947
|
+
const etherscanParamsSchema = discriminatedUnionType('type', [gasSchema, txnSchema]);
|
|
17852
17948
|
|
|
17853
|
-
|
|
17854
|
-
if (!Array.isArray(data)) return []
|
|
17949
|
+
/* global window */
|
|
17855
17950
|
|
|
17856
|
-
|
|
17857
|
-
|
|
17858
|
-
|
|
17859
|
-
|
|
17860
|
-
|
|
17861
|
-
|
|
17862
|
-
|
|
17863
|
-
|
|
17864
|
-
|
|
17951
|
+
|
|
17952
|
+
|
|
17953
|
+
|
|
17954
|
+
|
|
17955
|
+
|
|
17956
|
+
async function ETHERSCAN() {
|
|
17957
|
+
try {
|
|
17958
|
+
const [type, chain, address, startDate, endDate, page = 1, limit = 10] =
|
|
17959
|
+
argsToArray(arguments);
|
|
17960
|
+
|
|
17961
|
+
|
|
17962
|
+
validateParams(etherscanParamsSchema, { type, chain, address, startDate, endDate, page, limit });
|
|
17963
|
+
|
|
17964
|
+
const chainId = CHAIN_ID_MAP[chain];
|
|
17965
|
+
if (!chainId) throw new ValidationError(`Invalid chain: ${chain}`)
|
|
17966
|
+
|
|
17967
|
+
const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Etherscan);
|
|
17968
|
+
|
|
17969
|
+
return await handleScanRequest({
|
|
17970
|
+
type,
|
|
17971
|
+
address,
|
|
17972
|
+
startDate,
|
|
17973
|
+
endDate,
|
|
17974
|
+
page,
|
|
17975
|
+
offset: limit,
|
|
17976
|
+
apiKey,
|
|
17977
|
+
functionName: 'ETHERSCAN',
|
|
17978
|
+
chainId,
|
|
17979
|
+
network: chain,
|
|
17865
17980
|
})
|
|
17866
17981
|
} catch (err) {
|
|
17867
|
-
return errorMessageHandler(err, '
|
|
17982
|
+
return errorMessageHandler(err, 'ETHERSCAN')
|
|
17868
17983
|
}
|
|
17869
17984
|
}
|
|
17985
|
+
|
|
17986
|
+
const farcasterParamsSchema = objectType({
|
|
17987
|
+
contentType: enumType(['posts', 'replies', 'channels']),
|
|
17988
|
+
identifier: stringType().nonempty(),
|
|
17989
|
+
start: numberType().int().nonnegative().default(0),
|
|
17990
|
+
end: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"end" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
17991
|
+
});
|
|
17992
|
+
|
|
17993
|
+
/* global window */
|
|
17994
|
+
|
|
17995
|
+
|
|
17996
|
+
|
|
17997
|
+
|
|
17998
|
+
|
|
17999
|
+
|
|
18000
|
+
|
|
18001
|
+
|
|
17870
18002
|
async function FARCASTER() {
|
|
17871
18003
|
try {
|
|
17872
18004
|
const [contentType, identifier, start = 0, end = 10] =
|
|
@@ -17933,102 +18065,108 @@ async function FARCASTER() {
|
|
|
17933
18065
|
}
|
|
17934
18066
|
}
|
|
17935
18067
|
|
|
18068
|
+
const farcasterSchema = objectType({
|
|
18069
|
+
platform: literalType('farcaster'),
|
|
18070
|
+
contentType: enumType(['posts', 'replies', 'channels']),
|
|
18071
|
+
identifier: stringType().nonempty(),
|
|
18072
|
+
start: numberType().int().nonnegative().default(0),
|
|
18073
|
+
end: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"end" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
18074
|
+
});
|
|
18075
|
+
|
|
18076
|
+
const lensSchema = objectType({
|
|
18077
|
+
platform: literalType('lens'),
|
|
18078
|
+
contentType: enumType(['posts', 'replies']),
|
|
18079
|
+
identifier: stringType().nonempty(),
|
|
18080
|
+
start: numberType().int().nonnegative().default(0),
|
|
18081
|
+
end: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"end" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
18082
|
+
});
|
|
17936
18083
|
|
|
17937
|
-
|
|
17938
|
-
|
|
17939
|
-
|
|
17940
|
-
|
|
17941
|
-
|
|
17942
|
-
|
|
17943
|
-
|
|
17944
|
-
|
|
17945
|
-
|
|
17946
|
-
|
|
17947
|
-
|
|
18084
|
+
const fireflyParamsSchema = discriminatedUnionType('platform', [
|
|
18085
|
+
farcasterSchema,
|
|
18086
|
+
lensSchema,
|
|
18087
|
+
]);
|
|
18088
|
+
const fireFlyPlaformType = {
|
|
18089
|
+
farcaster: {
|
|
18090
|
+
posts: 'farcasterid',
|
|
18091
|
+
replies: 'farcasterpostid',
|
|
18092
|
+
channels: 'farcasterchannels'
|
|
18093
|
+
},
|
|
18094
|
+
lens: {
|
|
18095
|
+
posts: 'lensid',
|
|
18096
|
+
replies: 'lenspostid'
|
|
18097
|
+
}
|
|
18098
|
+
};
|
|
17948
18099
|
|
|
17949
|
-
|
|
17950
|
-
address,
|
|
17951
|
-
type,
|
|
17952
|
-
chain,
|
|
17953
|
-
startTimestamp,
|
|
17954
|
-
endTimestamp,
|
|
17955
|
-
page,
|
|
17956
|
-
offset
|
|
17957
|
-
});
|
|
18100
|
+
/* global window */
|
|
17958
18101
|
|
|
17959
|
-
const startTs =
|
|
17960
|
-
startTimestamp ?? Math.floor((Date.now() - 30 * 24 * 3600 * 1000) / 1000);
|
|
17961
|
-
const endTs = endTimestamp;
|
|
17962
18102
|
|
|
17963
|
-
const resolvedAddress = await fromEnsNameToAddress$1.validateAndGetAddress(address);
|
|
17964
18103
|
|
|
17965
|
-
const hostname = BLOCKSCOUT_CHAINS_MAP[chain];
|
|
17966
18104
|
|
|
17967
|
-
let requestUrl;
|
|
17968
|
-
switch (type) {
|
|
17969
|
-
case 'stat':
|
|
17970
|
-
requestUrl = `${hostname}/api/v2/addresses/${resolvedAddress}/counters`;
|
|
17971
|
-
break
|
|
17972
|
-
case 'txns':
|
|
17973
|
-
requestUrl =
|
|
17974
|
-
`${hostname}/api?module=account&action=txlist` +
|
|
17975
|
-
`&address=${resolvedAddress}` +
|
|
17976
|
-
`&start_timestamp=${startTs}` +
|
|
17977
|
-
`&end_timestamp=${endTs ?? ''}` +
|
|
17978
|
-
`&page=${page}` +
|
|
17979
|
-
`&offset=${offset}` +
|
|
17980
|
-
`&sort=asc`;
|
|
17981
|
-
break
|
|
17982
|
-
case 'tokens':
|
|
17983
|
-
requestUrl =
|
|
17984
|
-
`${hostname}/api?module=account&action=tokenlist` +
|
|
17985
|
-
`&address=${resolvedAddress}`;
|
|
17986
|
-
break
|
|
17987
|
-
}
|
|
17988
18105
|
|
|
17989
|
-
|
|
18106
|
+
|
|
18107
|
+
async function FIREFLY() {
|
|
18108
|
+
try {
|
|
18109
|
+
const [platform, contentType, identifier, start = 0, end = 10] = argsToArray(arguments);
|
|
18110
|
+
|
|
18111
|
+
validateParams(fireflyParamsSchema, {
|
|
18112
|
+
platform,
|
|
18113
|
+
contentType,
|
|
18114
|
+
identifier,
|
|
18115
|
+
start,
|
|
18116
|
+
end,
|
|
18117
|
+
});
|
|
18118
|
+
|
|
18119
|
+
const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Firefly);
|
|
18120
|
+
|
|
18121
|
+
const url = new URL('https://openapi.firefly.land/v1/fileverse/fetch');
|
|
18122
|
+
url.searchParams
|
|
18123
|
+
.set('query',
|
|
18124
|
+
identifier
|
|
18125
|
+
.split(',')
|
|
18126
|
+
.map(s => s.trim())
|
|
18127
|
+
.filter(Boolean)
|
|
18128
|
+
.join(',')
|
|
18129
|
+
);
|
|
18130
|
+
url.searchParams.set('type', fireFlyPlaformType[platform][contentType]);
|
|
18131
|
+
url.searchParams.set('start', String(start));
|
|
18132
|
+
url.searchParams.set('end', String(end));
|
|
18133
|
+
|
|
18134
|
+
const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url: url.toString(), serviceName: 'Firefly', headers: { 'x-api-key': apiKey } });
|
|
18135
|
+
const response = await fetch(finalUrl, {
|
|
18136
|
+
method: 'GET',
|
|
18137
|
+
headers: HEADERS,
|
|
18138
|
+
});
|
|
17990
18139
|
if (!response.ok) {
|
|
17991
|
-
throw new NetworkError(
|
|
18140
|
+
throw new NetworkError(SERVICES_API_KEY.Firefly, response.status)
|
|
17992
18141
|
}
|
|
17993
18142
|
|
|
17994
|
-
const
|
|
17995
|
-
|
|
17996
|
-
|
|
17997
|
-
if (json?.result?.includes('Invalid parameter(s)')) {
|
|
17998
|
-
throw new ValidationError('Invalid parameters')
|
|
17999
|
-
}
|
|
18000
|
-
if (json?.result?.includes('Not found')) {
|
|
18001
|
-
throw new ValidationError('Address information not found')
|
|
18143
|
+
const { data } = await response.json();
|
|
18144
|
+
if (!Array.isArray(data)) {
|
|
18145
|
+
return []
|
|
18002
18146
|
}
|
|
18147
|
+
return data.map(item => {
|
|
18148
|
+
const flat = {};
|
|
18149
|
+
for (const [key, value] of Object.entries(item)) {
|
|
18150
|
+
if (typeof value !== 'object' || value === null) {
|
|
18151
|
+
flat[key] = value;
|
|
18152
|
+
}
|
|
18153
|
+
}
|
|
18154
|
+
flat.platform = platform;
|
|
18155
|
+
return flat
|
|
18156
|
+
})
|
|
18003
18157
|
|
|
18004
|
-
return type === 'stat' ? [json] : json.result
|
|
18005
18158
|
} catch (err) {
|
|
18006
|
-
return errorMessageHandler(err, '
|
|
18159
|
+
return errorMessageHandler(err, 'FIREFLY')
|
|
18007
18160
|
}
|
|
18008
18161
|
}
|
|
18009
18162
|
|
|
18010
|
-
|
|
18011
|
-
|
|
18012
|
-
|
|
18013
|
-
|
|
18014
|
-
|
|
18163
|
+
/* global window */
|
|
18164
|
+
|
|
18165
|
+
|
|
18166
|
+
|
|
18167
|
+
|
|
18168
|
+
|
|
18015
18169
|
|
|
18016
|
-
return await handleScanRequest({
|
|
18017
|
-
type,
|
|
18018
|
-
address,
|
|
18019
|
-
startDate,
|
|
18020
|
-
endDate,
|
|
18021
|
-
page,
|
|
18022
|
-
offset: limit,
|
|
18023
|
-
apiKey: API_KEY,
|
|
18024
|
-
functionName: 'BASE',
|
|
18025
|
-
chainId: CHAIN_ID_MAP.base,
|
|
18026
|
-
network: 'base'
|
|
18027
|
-
})
|
|
18028
|
-
} catch (error) {
|
|
18029
|
-
return errorMessageHandler(error, 'BASE')
|
|
18030
|
-
}
|
|
18031
|
-
}
|
|
18032
18170
|
async function GNOSIS() {
|
|
18033
18171
|
try {
|
|
18034
18172
|
const [type, address, startDate, endDate, page = 1, limit = 10] =
|
|
@@ -18065,306 +18203,178 @@ async function GNOSIS() {
|
|
|
18065
18203
|
}
|
|
18066
18204
|
}
|
|
18067
18205
|
|
|
18068
|
-
|
|
18069
|
-
|
|
18070
|
-
|
|
18071
|
-
|
|
18072
|
-
|
|
18073
|
-
|
|
18074
|
-
const [username] = argsToArray(arguments);
|
|
18075
|
-
|
|
18076
|
-
validateParams(neynarParamsSchema, { username });
|
|
18077
|
-
|
|
18078
|
-
const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Neynar);
|
|
18079
|
-
|
|
18080
|
-
const fid = await fromUsernameToFid$1.fromUsernameToFid(username, apiKey);
|
|
18081
|
-
if (!fid) throw new ValidationError(`Invalid username: ${username}`)
|
|
18082
|
-
|
|
18083
|
-
const url = `https://api.neynar.com/v2/farcaster/followers?fid=${fid}`;
|
|
18084
|
-
|
|
18085
|
-
const { URL: finalUrl, HEADERS } = getUrlAndHeaders({
|
|
18086
|
-
url: url.toString(), serviceName: 'Neynar',
|
|
18087
|
-
headers: {
|
|
18088
|
-
'x-api-key': apiKey,
|
|
18089
|
-
'x-neynar-experimental': 'false'
|
|
18090
|
-
}
|
|
18091
|
-
|
|
18092
|
-
});
|
|
18093
|
-
|
|
18094
|
-
const response = await fetch(finalUrl, {
|
|
18095
|
-
method: 'GET',
|
|
18096
|
-
headers: HEADERS,
|
|
18097
|
-
});
|
|
18098
|
-
if (!response.ok) {
|
|
18099
|
-
throw new NetworkError(SERVICES_API_KEY.Neynar, response.status)
|
|
18100
|
-
}
|
|
18101
|
-
|
|
18102
|
-
const json = await response.json();
|
|
18103
|
-
const users = json?.users || [];
|
|
18104
|
-
if (!users.length) return []
|
|
18105
|
-
|
|
18106
|
-
return users.map(({ user }) => ({
|
|
18107
|
-
username: user.username,
|
|
18108
|
-
custody_address: user.custody_address,
|
|
18109
|
-
follower_count: user.follower_count,
|
|
18110
|
-
country: user.profile?.location?.address?.country || '',
|
|
18111
|
-
city: user.profile?.location?.address?.city || '',
|
|
18112
|
-
}))
|
|
18113
|
-
} catch (err) {
|
|
18114
|
-
return errorMessageHandler(err, 'NEYNAR')
|
|
18115
|
-
}
|
|
18116
|
-
}
|
|
18206
|
+
const lensParamsSchema = objectType({
|
|
18207
|
+
contentType: enumType(['posts', 'replies']),
|
|
18208
|
+
identifier: stringType().nonempty(),
|
|
18209
|
+
start: numberType().int().nonnegative().default(0),
|
|
18210
|
+
end: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"end" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
18211
|
+
});
|
|
18117
18212
|
|
|
18118
|
-
|
|
18119
|
-
// cardId,
|
|
18120
|
-
// startDate,
|
|
18121
|
-
// endDate,
|
|
18122
|
-
// limit = 20,
|
|
18123
|
-
// offset = 0,
|
|
18124
|
-
// }) {
|
|
18125
|
-
// const apiKeyKey = SERVICES_API_KEY.GnosisPay
|
|
18126
|
-
// const API_KEY = window.localStorage.getItem(apiKeyKey);
|
|
18127
|
-
// if (!API_KEY) return `${apiKeyKey}${ERROR_MESSAGES_FLAG.MISSING_KEY}`;
|
|
18128
|
-
// if (!cardId) return `${apiKeyKey}${ERROR_MESSAGES_FLAG.INVALID_PARAM}`;
|
|
18129
|
-
// if(limit > MAX_PAGE_LIMIT){
|
|
18130
|
-
// return ERROR_MESSAGES_FLAG.MAX_PAGE_LIMIT
|
|
18131
|
-
// }
|
|
18213
|
+
/* global window */
|
|
18132
18214
|
|
|
18133
|
-
// const url = new URL(`https://api.gnosispay.com/cards/${cardId}/transactions`);
|
|
18134
|
-
// url.searchParams.set('limit', limit.toString());
|
|
18135
|
-
// url.searchParams.set('offset', offset.toString());
|
|
18136
18215
|
|
|
18137
|
-
// if (!isNaN(toTimestamp(startDate))) {
|
|
18138
|
-
// url.searchParams.set('startDate', new Date(startDate * 1000).toISOString());
|
|
18139
|
-
// }
|
|
18140
18216
|
|
|
18141
|
-
// if (!isNaN(toTimestamp(endDate))) {
|
|
18142
|
-
// url.searchParams.set('endDate', new Date(endDate * 1000).toISOString());
|
|
18143
|
-
// }
|
|
18144
18217
|
|
|
18145
|
-
// try {
|
|
18146
|
-
// const res = await fetch(url.toString(), {
|
|
18147
|
-
// headers: {
|
|
18148
|
-
// Authorization: `Bearer ${API_KEY}`,
|
|
18149
|
-
// 'Content-Type': 'application/json',
|
|
18150
|
-
// },
|
|
18151
|
-
// });
|
|
18152
|
-
|
|
18153
|
-
// if (!res.ok) throw new Error(`HTTP error! Status: ${res.status}`);
|
|
18154
|
-
|
|
18155
|
-
// const json = await res.json();
|
|
18156
|
-
|
|
18157
|
-
// if (!Array.isArray(json)) return [];
|
|
18158
|
-
|
|
18159
|
-
// return json.map(tx => ({
|
|
18160
|
-
// createdAt: tx.createdAt,
|
|
18161
|
-
// clearedAt: tx.clearedAt,
|
|
18162
|
-
// country: tx.country,
|
|
18163
|
-
// merchant: tx.merchant,
|
|
18164
|
-
// billingAmount: tx.billingAmount,
|
|
18165
|
-
// billingCurrency: tx.billingCurrency,
|
|
18166
|
-
// transactionAmount: tx.transactionAmount,
|
|
18167
|
-
// transactionCurrency: tx.transactionCurrency,
|
|
18168
|
-
// transactionType: tx.transactionType,
|
|
18169
|
-
// kind: tx.kind,
|
|
18170
|
-
// status: tx.status || null,
|
|
18171
|
-
// mcc: tx.mcc,
|
|
18172
|
-
// }));
|
|
18173
|
-
// } catch (err) {
|
|
18174
|
-
// console.error('GNOSISPAY_CARD_TXNS error:', err);
|
|
18175
|
-
// return ERROR_MESSAGES_FLAG.DEFAULT;
|
|
18176
|
-
// }
|
|
18177
|
-
// }
|
|
18178
18218
|
|
|
18179
|
-
async function
|
|
18219
|
+
async function LENS() {
|
|
18180
18220
|
try {
|
|
18181
|
-
const [
|
|
18221
|
+
const [contentType, identifier, start = 0, end = 10] =
|
|
18182
18222
|
argsToArray(arguments);
|
|
18183
18223
|
|
|
18224
|
+
validateParams(lensParamsSchema, {
|
|
18225
|
+
contentType,
|
|
18226
|
+
identifier,
|
|
18227
|
+
start,
|
|
18228
|
+
end,
|
|
18229
|
+
});
|
|
18184
18230
|
|
|
18185
|
-
|
|
18186
|
-
|
|
18187
|
-
|
|
18188
|
-
if (!chainId) throw new ValidationError(`Invalid chain: ${chain}`)
|
|
18189
|
-
|
|
18190
|
-
const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Etherscan);
|
|
18191
|
-
|
|
18192
|
-
return await handleScanRequest({
|
|
18193
|
-
type,
|
|
18194
|
-
address,
|
|
18195
|
-
startDate,
|
|
18196
|
-
endDate,
|
|
18197
|
-
page,
|
|
18198
|
-
offset: limit,
|
|
18199
|
-
apiKey,
|
|
18200
|
-
functionName: 'ETHERSCAN',
|
|
18201
|
-
chainId,
|
|
18202
|
-
network: chain,
|
|
18203
|
-
})
|
|
18204
|
-
} catch (err) {
|
|
18205
|
-
return errorMessageHandler(err, 'ETHERSCAN')
|
|
18206
|
-
}
|
|
18207
|
-
}
|
|
18208
|
-
|
|
18209
|
-
|
|
18210
|
-
async function COINGECKO() {
|
|
18211
|
-
try {
|
|
18212
|
-
const [category, param1, param2] = argsToArray(arguments);
|
|
18213
|
-
validateParams(coingeckoParamsSchema, { category, param1, param2 });
|
|
18214
|
-
|
|
18215
|
-
const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Coingecko);
|
|
18231
|
+
const apiKey = window.localStorage.getItem(
|
|
18232
|
+
SERVICES_API_KEY.Firefly
|
|
18233
|
+
);
|
|
18216
18234
|
|
|
18217
|
-
const
|
|
18218
|
-
|
|
18219
|
-
|
|
18235
|
+
const url = new URL(
|
|
18236
|
+
'https://openapi.firefly.land/v1/fileverse/fetch'
|
|
18237
|
+
);
|
|
18238
|
+
url.searchParams.set(
|
|
18239
|
+
'query',
|
|
18240
|
+
identifier
|
|
18241
|
+
.split(',')
|
|
18242
|
+
.map((s) => s.trim())
|
|
18243
|
+
.filter(Boolean)
|
|
18244
|
+
.join(',')
|
|
18245
|
+
);
|
|
18246
|
+
const typeMap = {
|
|
18247
|
+
posts: 'lensid',
|
|
18248
|
+
replies: 'lenspostid',
|
|
18220
18249
|
};
|
|
18221
|
-
|
|
18222
|
-
|
|
18223
|
-
|
|
18224
|
-
const vs = param2 || 'usd';
|
|
18225
|
-
url = `https://api.coingecko.com/api/v3/simple/price?vs_currencies=${vs}&symbols=${param1}`;
|
|
18226
|
-
break
|
|
18227
|
-
}
|
|
18228
|
-
case 'market': {
|
|
18229
|
-
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' };
|
|
18230
|
-
const _category = map[param1] || '';
|
|
18231
|
-
const trend = param2 ? `&price_change_percentage=${param2}` : '';
|
|
18232
|
-
url = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&include_tokens=top&page=1&per_page=100${_category ? `&category=${_category}` : ''}${trend}`;
|
|
18233
|
-
break
|
|
18234
|
-
}
|
|
18235
|
-
case 'stablecoins': {
|
|
18236
|
-
const _category = param1 === 'all' ? 'stablecoins' : param1;
|
|
18237
|
-
const trend = param2 ? `&price_change_percentage=${param2}` : '';
|
|
18238
|
-
url = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&category=${_category}&order=market_cap_desc&page=1&per_page=100${trend}`;
|
|
18239
|
-
break
|
|
18240
|
-
}
|
|
18241
|
-
case 'derivatives': {
|
|
18242
|
-
url = (!param1 || param1 === 'all')
|
|
18243
|
-
? 'https://api.coingecko.com/api/v3/derivatives'
|
|
18244
|
-
: `https://api.coingecko.com/api/v3/derivatives/exchanges/${param1}?include_tickers=all`;
|
|
18245
|
-
break
|
|
18246
|
-
}
|
|
18247
|
-
}
|
|
18248
|
-
const {URL: finalUrl, HEADERS} = getUrlAndHeaders({url, serviceName: 'Coingecko', headers});
|
|
18250
|
+
url.searchParams.set('type', typeMap[contentType]);
|
|
18251
|
+
url.searchParams.set('start', String(start));
|
|
18252
|
+
url.searchParams.set('end', String(end));
|
|
18249
18253
|
|
|
18250
|
-
const
|
|
18251
|
-
|
|
18252
|
-
|
|
18253
|
-
|
|
18254
|
-
|
|
18255
|
-
|
|
18254
|
+
const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url: url.toString(), serviceName: 'Firefly', headers: { 'x-api-key': apiKey } });
|
|
18255
|
+
|
|
18256
|
+
const response = await fetch(finalUrl, {
|
|
18257
|
+
method: 'GET',
|
|
18258
|
+
headers: HEADERS,
|
|
18259
|
+
});
|
|
18260
|
+
if (!response.ok) {
|
|
18261
|
+
throw new NetworkError(SERVICES_API_KEY.Firefly, response.status)
|
|
18256
18262
|
}
|
|
18257
18263
|
|
|
18258
|
-
|
|
18259
|
-
|
|
18260
|
-
for (const [token, prices] of Object.entries(json))
|
|
18261
|
-
for (const [cur, val] of Object.entries(prices))
|
|
18262
|
-
out[`${token.charAt(0).toUpperCase() + token.slice(1)}_${cur.toUpperCase()}`] = val;
|
|
18263
|
-
return [out]
|
|
18264
|
-
}
|
|
18264
|
+
const { data } = await response.json();
|
|
18265
|
+
if (!Array.isArray(data)) return []
|
|
18265
18266
|
|
|
18266
|
-
|
|
18267
|
-
return data.map(item => {
|
|
18267
|
+
return data.map((item) => {
|
|
18268
18268
|
const flat = {};
|
|
18269
18269
|
for (const [key, value] of Object.entries(item)) {
|
|
18270
|
-
if (typeof value !== 'object'
|
|
18270
|
+
if (value == null || typeof value !== 'object') {
|
|
18271
18271
|
flat[key] = value;
|
|
18272
18272
|
}
|
|
18273
18273
|
}
|
|
18274
|
+
flat.platform = 'lens';
|
|
18274
18275
|
return flat
|
|
18275
18276
|
})
|
|
18276
18277
|
} catch (err) {
|
|
18277
|
-
return errorMessageHandler(err, '
|
|
18278
|
+
return errorMessageHandler(err, 'LENS')
|
|
18278
18279
|
}
|
|
18279
18280
|
}
|
|
18280
18281
|
|
|
18281
|
-
|
|
18282
|
-
|
|
18283
|
-
|
|
18284
|
-
argsToArray(arguments);
|
|
18285
|
-
validateParams(eoaParamsSchema, { addresses, category, chains, startTime, endTime, page, offset });
|
|
18282
|
+
const neynarParamsSchema = objectType({
|
|
18283
|
+
username: stringType().nonempty()
|
|
18284
|
+
});
|
|
18286
18285
|
|
|
18287
|
-
|
|
18286
|
+
const fromUsernameToFid = async (username, apiKey) => {
|
|
18287
|
+
if (!username) return null
|
|
18288
|
+
const url = `https://api.neynar.com/v2/farcaster/user/search/?q=${username}&limit=5`;
|
|
18289
|
+
const { URL: finalUrl, HEADERS } = getUrlAndHeaders({
|
|
18290
|
+
url, serviceName: 'Neynar', headers: {
|
|
18291
|
+
'x-api-key': apiKey,
|
|
18292
|
+
'x-neynar-experimental': 'false'
|
|
18293
|
+
}
|
|
18294
|
+
});
|
|
18288
18295
|
|
|
18289
|
-
|
|
18290
|
-
|
|
18296
|
+
const res = await fetch(finalUrl, {
|
|
18297
|
+
method: 'GET',
|
|
18298
|
+
headers: HEADERS,
|
|
18299
|
+
});
|
|
18300
|
+
const json = await res.json();
|
|
18301
|
+
const users = json.result ? json.result.users : [];
|
|
18302
|
+
const user = users.find(user => user.username === username);
|
|
18303
|
+
return user && user.fid || null;
|
|
18304
|
+
};
|
|
18305
|
+
var fromUsernameToFid$1 = {
|
|
18306
|
+
fromUsernameToFid
|
|
18307
|
+
};
|
|
18291
18308
|
|
|
18292
|
-
|
|
18293
|
-
for (const inp of INPUTS) {
|
|
18294
|
-
if (isAddress$1.isAddress(inp)) {
|
|
18295
|
-
ADDRESS_MAP[inp.toLowerCase()] = null;
|
|
18296
|
-
} else {
|
|
18297
|
-
const _address = await fromEnsNameToAddress$1.validateAndGetAddress(inp);
|
|
18298
|
-
ADDRESS_MAP[_address.toLowerCase()] = _address;
|
|
18299
|
-
}
|
|
18300
|
-
}
|
|
18301
|
-
const ADDRS = Object.keys(ADDRESS_MAP);
|
|
18302
|
-
const out = [];
|
|
18309
|
+
/* global window */
|
|
18303
18310
|
|
|
18304
|
-
async function fetchJSON(url) {
|
|
18305
|
-
const { URL: finalUrl, HEADERS } = getUrlAndHeaders({ url, serviceName: 'Etherscan', headers: {} });
|
|
18306
|
-
const res = await fetch(finalUrl, {
|
|
18307
|
-
method: 'GET',
|
|
18308
|
-
headers: HEADERS,
|
|
18309
|
-
});
|
|
18310
|
-
if (!res.ok) throw new NetworkError(SERVICES_API_KEY.Etherscan, res.status)
|
|
18311
|
-
const json = await res.json();
|
|
18312
18311
|
|
|
18313
|
-
if (typeof json.result === 'string') {
|
|
18314
|
-
if (json.result.includes('Invalid API Key')) throw new InvalidApiKeyError(SERVICES_API_KEY.Etherscan)
|
|
18315
|
-
if (json.result.includes('Max rate limit reached')) throw new RateLimitError(SERVICES_API_KEY.Etherscan)
|
|
18316
|
-
}
|
|
18317
|
-
return json.result
|
|
18318
|
-
}
|
|
18319
18312
|
|
|
18320
18313
|
|
|
18321
|
-
for (const chain of CHAINS) {
|
|
18322
|
-
const chainId = CHAIN_ID_MAP[chain];
|
|
18323
|
-
if (!chainId) throw new ValidationError(`Invalid chain: ${chain}`)
|
|
18324
18314
|
|
|
18325
|
-
|
|
18326
|
-
|
|
18327
|
-
|
|
18328
|
-
|
|
18329
|
-
|
|
18330
|
-
|
|
18331
|
-
|
|
18332
|
-
|
|
18333
|
-
|
|
18334
|
-
|
|
18335
|
-
|
|
18336
|
-
|
|
18337
|
-
|
|
18338
|
-
|
|
18339
|
-
|
|
18340
|
-
|
|
18341
|
-
|
|
18342
|
-
|
|
18343
|
-
|
|
18344
|
-
|
|
18345
|
-
|
|
18346
|
-
|
|
18347
|
-
`&startblock=${sb}&endblock=${eb}` +
|
|
18348
|
-
`&page=${page}&offset=${offset}&sort=asc&apikey=${apiKey}`;
|
|
18349
|
-
const data = await fetchJSON(url);
|
|
18350
|
-
if (!Array.isArray(data)) return data
|
|
18351
|
-
data.forEach(item => out.push({ chain, address: addr, name: ADDRESS_MAP[addr], ...item }));
|
|
18315
|
+
|
|
18316
|
+
|
|
18317
|
+
async function NEYNAR() {
|
|
18318
|
+
try {
|
|
18319
|
+
|
|
18320
|
+
|
|
18321
|
+
const [username] = argsToArray(arguments);
|
|
18322
|
+
|
|
18323
|
+
validateParams(neynarParamsSchema, { username });
|
|
18324
|
+
|
|
18325
|
+
const apiKey = window.localStorage.getItem(SERVICES_API_KEY.Neynar);
|
|
18326
|
+
|
|
18327
|
+
const fid = await fromUsernameToFid$1.fromUsernameToFid(username, apiKey);
|
|
18328
|
+
if (!fid) throw new ValidationError(`Invalid username: ${username}`)
|
|
18329
|
+
|
|
18330
|
+
const url = `https://api.neynar.com/v2/farcaster/followers?fid=${fid}`;
|
|
18331
|
+
|
|
18332
|
+
const { URL: finalUrl, HEADERS } = getUrlAndHeaders({
|
|
18333
|
+
url: url.toString(), serviceName: 'Neynar',
|
|
18334
|
+
headers: {
|
|
18335
|
+
'x-api-key': apiKey,
|
|
18336
|
+
'x-neynar-experimental': 'false'
|
|
18352
18337
|
}
|
|
18353
|
-
|
|
18338
|
+
|
|
18339
|
+
});
|
|
18340
|
+
|
|
18341
|
+
const response = await fetch(finalUrl, {
|
|
18342
|
+
method: 'GET',
|
|
18343
|
+
headers: HEADERS,
|
|
18344
|
+
});
|
|
18345
|
+
if (!response.ok) {
|
|
18346
|
+
throw new NetworkError(SERVICES_API_KEY.Neynar, response.status)
|
|
18354
18347
|
}
|
|
18355
|
-
|
|
18348
|
+
|
|
18349
|
+
const json = await response.json();
|
|
18350
|
+
const users = json?.users || [];
|
|
18351
|
+
if (!users.length) return []
|
|
18352
|
+
|
|
18353
|
+
return users.map(({ user }) => ({
|
|
18354
|
+
username: user.username,
|
|
18355
|
+
custody_address: user.custody_address,
|
|
18356
|
+
follower_count: user.follower_count,
|
|
18357
|
+
country: user.profile?.location?.address?.country || '',
|
|
18358
|
+
city: user.profile?.location?.address?.city || '',
|
|
18359
|
+
}))
|
|
18356
18360
|
} catch (err) {
|
|
18357
|
-
return errorMessageHandler(err, '
|
|
18361
|
+
return errorMessageHandler(err, 'NEYNAR')
|
|
18358
18362
|
}
|
|
18359
18363
|
}
|
|
18360
18364
|
|
|
18361
|
-
|
|
18362
|
-
|
|
18363
|
-
|
|
18364
|
-
|
|
18365
|
-
|
|
18366
|
-
|
|
18367
|
-
}
|
|
18365
|
+
const safeParamsSchema = objectType({
|
|
18366
|
+
address: stringType().nonempty(),
|
|
18367
|
+
utility: literalType('txns'),
|
|
18368
|
+
chain: enumType(['ethereum','gnosis']),
|
|
18369
|
+
limit: numberType().int().nonnegative().max(MAX_PAGE_LIMIT, {message: `"limit" must be less than or equal to ${MAX_PAGE_LIMIT}`}).default(10),
|
|
18370
|
+
offset: numberType().int().nonnegative().default(0),
|
|
18371
|
+
});
|
|
18372
|
+
|
|
18373
|
+
/* global window */
|
|
18374
|
+
|
|
18375
|
+
|
|
18376
|
+
|
|
18377
|
+
|
|
18368
18378
|
|
|
18369
18379
|
async function SAFE() {
|
|
18370
18380
|
try {
|
|
@@ -18401,42 +18411,12 @@ async function SAFE() {
|
|
|
18401
18411
|
}
|
|
18402
18412
|
}
|
|
18403
18413
|
|
|
18404
|
-
|
|
18405
|
-
|
|
18406
|
-
|
|
18407
|
-
|
|
18408
|
-
|
|
18409
|
-
|
|
18410
|
-
const url = CATEGORY_URLS[category];
|
|
18411
|
-
if (!url) throw new ValidationError(`Invalid category: ${category}`)
|
|
18412
|
-
const res = await fetch(url);
|
|
18413
|
-
if (!res.ok) throw new NetworkError(SERVICES_API_KEY.Defillama, res.status)
|
|
18414
|
-
let json = await res.json();
|
|
18415
|
-
|
|
18416
|
-
switch (category) {
|
|
18417
|
-
case 'protocols':
|
|
18418
|
-
json = Array.isArray(json) ? json.slice(0, 500) : [];
|
|
18419
|
-
break
|
|
18420
|
-
case 'yields':
|
|
18421
|
-
json = Array.isArray(json.data) ? json.data.slice(0, 500) : [];
|
|
18422
|
-
break
|
|
18423
|
-
case 'dex':
|
|
18424
|
-
case 'fees':
|
|
18425
|
-
json = Array.isArray(json.protocols) ? json.protocols.slice(0, 500) : [];
|
|
18426
|
-
break
|
|
18427
|
-
}
|
|
18428
|
-
|
|
18429
|
-
return (Array.isArray(json) ? json : [json]).map(item => {
|
|
18430
|
-
const out = {};
|
|
18431
|
-
for (const [k, v] of Object.entries(item)) {
|
|
18432
|
-
if (v === null || typeof v !== 'object') out[k] = v;
|
|
18433
|
-
}
|
|
18434
|
-
return out
|
|
18435
|
-
})
|
|
18436
|
-
} catch (err) {
|
|
18437
|
-
return errorMessageHandler(err, 'DEFILLAMA')
|
|
18438
|
-
}
|
|
18439
|
-
}
|
|
18414
|
+
const uniswapParamsSchema = objectType({
|
|
18415
|
+
graphType: enumType(['v3','v3-raw']),
|
|
18416
|
+
category: enumType(['tokens','markets']),
|
|
18417
|
+
param1: stringType().nonempty(),
|
|
18418
|
+
param2: stringType().optional(),
|
|
18419
|
+
});
|
|
18440
18420
|
|
|
18441
18421
|
async function UNISWAP() {
|
|
18442
18422
|
try {
|
|
@@ -18476,43 +18456,12 @@ async function UNISWAP() {
|
|
|
18476
18456
|
}
|
|
18477
18457
|
}
|
|
18478
18458
|
|
|
18479
|
-
|
|
18480
|
-
|
|
18481
|
-
|
|
18482
|
-
|
|
18483
|
-
|
|
18484
|
-
|
|
18485
|
-
|
|
18486
|
-
validateParams(aaveParamsSchema, { graphType, category, param1, param2 });
|
|
18487
|
-
|
|
18488
|
-
const baseUrl = 'https://onchain-proxy.fileverse.io/third-party';
|
|
18489
|
-
const url =
|
|
18490
|
-
`${baseUrl}` +
|
|
18491
|
-
`?service=aave` +
|
|
18492
|
-
`&graphType=${encodeURIComponent(graphType)}` +
|
|
18493
|
-
`&category=${encodeURIComponent(category)}` +
|
|
18494
|
-
`&input1=${encodeURIComponent(param1)}` +
|
|
18495
|
-
(param2 ? `&input2=${encodeURIComponent(param2)}` : '');
|
|
18496
|
-
|
|
18497
|
-
const res = await fetch(url);
|
|
18498
|
-
if (!res.ok) {
|
|
18499
|
-
throw new NetworkError('AAVE', res.status)
|
|
18500
|
-
}
|
|
18501
|
-
|
|
18502
|
-
const json = await res.json();
|
|
18503
|
-
if (Array.isArray(json)) {
|
|
18504
|
-
return json.map(item => {
|
|
18505
|
-
const flat = {};
|
|
18506
|
-
Object.entries(item).forEach(([k, v]) => {
|
|
18507
|
-
if (v === null || typeof v !== 'object') flat[k] = v;
|
|
18508
|
-
});
|
|
18509
|
-
return flat
|
|
18510
|
-
})
|
|
18511
|
-
}
|
|
18512
|
-
return json
|
|
18513
|
-
} catch (err) {
|
|
18514
|
-
return errorMessageHandler(err, 'AAVE')
|
|
18515
|
-
}
|
|
18459
|
+
async function FLVURL() {
|
|
18460
|
+
return new Promise((resolve) => {
|
|
18461
|
+
setTimeout(() => {
|
|
18462
|
+
resolve([{ Yoo: 'gotcha' }]);
|
|
18463
|
+
}, 10000);
|
|
18464
|
+
})
|
|
18516
18465
|
}
|
|
18517
18466
|
|
|
18518
18467
|
function POLYMARKET() {
|