mirror of
https://github.com/alexgo-io/DefiLlama-Adapters.git
synced 2026-01-12 08:34:23 +08:00
reduce idl file size
This commit is contained in:
@@ -14,7 +14,8 @@
|
||||
"treasury": "cd utils;npm i; cd ..; node utils/testInteractive treasury",
|
||||
"entities": "cd utils;npm i; cd ..; node utils/testInteractive entities",
|
||||
"useTokenLabels": "node utils/scripts/useTokenLabels.js",
|
||||
"biggest-files": "find ./projects -name '*.js' -not -path './projects/helper/*' -not -path './projects/curve/*' -not -path './projects/sigmao/*' -exec du -sh {} \\; | sort -rh | head -n 100",
|
||||
"_biggest-files-old": "find ./projects -name '*.js' -not -path './projects/helper/*' -not -path './projects/curve/*' -not -path './projects/sigmao/*' -exec du -sh {} \\; | sort -rh | head -n 100",
|
||||
"biggest-files": "node utils/scripts/sortTopFilesByLines.js",
|
||||
"check-bitcoin-duplicates": "node utils/scripts/checkBTCDupsv2.js",
|
||||
"string-timestamp": "node utils/scripts/stringTimestamp.js",
|
||||
"sort-chains": "node projects/helper/getChainList.js",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,6 @@
|
||||
|
||||
const { Program } = require("@project-serum/anchor");
|
||||
const { getProvider, sumTokens2, } = require("../helper/solana");
|
||||
const idl = require('./idl.json')
|
||||
|
||||
async function tvl() {
|
||||
const provider = getProvider()
|
||||
const program = new Program(idl, 'CYPH3o83JX6jY6NkbproSpdmQ5VWJtxjfJ5P8veyYVu3', provider)
|
||||
const pools = await program.account.pool.all()
|
||||
const tokenAccounts = pools.map(({ account }) => {
|
||||
return account.nodes.map(i => i.nodeVault.toString()).filter(i => i !== '11111111111111111111111111111111')
|
||||
}).flat()
|
||||
return sumTokens2({ tokenAccounts})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
// hallmarks: [
|
||||
// [1691373600,"exploit/security incident"] //https://twitter.com/cypher_protocol/status/1688641036476731393
|
||||
// ],
|
||||
deadFrom: '2023-08-07',
|
||||
timetravel: false,
|
||||
solana: { tvl, },
|
||||
solana: { tvl: () => ({}), },
|
||||
}
|
||||
|
||||
@@ -66,36 +66,36 @@ async function tvlSolana(api) {
|
||||
const idl = require("./drift_idl.json")
|
||||
const programId = new PublicKey('dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH')
|
||||
const provider = getProvider()
|
||||
const program = new Program(idl, programId, provider)
|
||||
const program = new Program(idl, programId, provider)
|
||||
|
||||
for (const account of accounts) {
|
||||
const userData = program.coder.accounts.decode("User", account.data);
|
||||
for (const spotPosition of userData.spotPositions) {
|
||||
if (!new BN(spotPosition.scaledBalance).isZero()) {
|
||||
const marketIndex = spotPosition.marketIndex
|
||||
const balanceType = Object.keys(spotPosition.balanceType ?? {})?.[0]
|
||||
const scaledBalance = new BN(spotPosition.scaledBalance)
|
||||
const token = getTokenInfo(true, marketIndex)
|
||||
if (!token) continue;
|
||||
const balance = scaledBalance
|
||||
.mul(new BN(balanceType === 'deposit' ? 1 : -1))
|
||||
.div(new BN(10).pow(new BN(token.decimals - 9)));
|
||||
|
||||
api.add(token.mint, balance.toString())
|
||||
}
|
||||
const userData = program.coder.accounts.decode("User", account.data);
|
||||
for (const spotPosition of userData.spotPositions) {
|
||||
if (!new BN(spotPosition.scaledBalance).isZero()) {
|
||||
const marketIndex = spotPosition.marketIndex
|
||||
const balanceType = Object.keys(spotPosition.balanceType ?? {})?.[0]
|
||||
const scaledBalance = new BN(spotPosition.scaledBalance)
|
||||
const token = getTokenInfo(true, marketIndex)
|
||||
if (!token) continue;
|
||||
const balance = scaledBalance
|
||||
.mul(new BN(balanceType === 'deposit' ? 1 : -1))
|
||||
.div(new BN(10).pow(new BN(token.decimals - 9)));
|
||||
|
||||
api.add(token.mint, balance.toString())
|
||||
}
|
||||
for (const perpPosition of userData.perpPositions) {
|
||||
if (!new BN(perpPosition.baseAssetAmount).isZero()) {
|
||||
const marketIndex = perpPosition.marketIndex
|
||||
const token = getTokenInfo(false, marketIndex)
|
||||
if (!token) continue;
|
||||
const baseAssetAmount = new BN(perpPosition.baseAssetAmount)
|
||||
.div(new BN(10).pow(new BN(token.decimals - 9)));
|
||||
const quoteAssetAmount = new BN(perpPosition.quoteAssetAmount)
|
||||
api.add(TOKEN_INFO['USDC'].mint, quoteAssetAmount.toString())
|
||||
api.add(token.mint, baseAssetAmount.toString())
|
||||
}
|
||||
}
|
||||
for (const perpPosition of userData.perpPositions) {
|
||||
if (!new BN(perpPosition.baseAssetAmount).isZero()) {
|
||||
const marketIndex = perpPosition.marketIndex
|
||||
const token = getTokenInfo(false, marketIndex)
|
||||
if (!token) continue;
|
||||
const baseAssetAmount = new BN(perpPosition.baseAssetAmount)
|
||||
.div(new BN(10).pow(new BN(token.decimals - 9)));
|
||||
const quoteAssetAmount = new BN(perpPosition.quoteAssetAmount)
|
||||
api.add(TOKEN_INFO['USDC'].mint, quoteAssetAmount.toString())
|
||||
api.add(token.mint, baseAssetAmount.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,54 +124,54 @@ async function tvlArbitrum(api) {
|
||||
const v2ReaderAbi = require('./v2_reader_abi.json');
|
||||
const v2ReaderAddress = '0xf60becbba223EEA9495Da3f606753867eC10d139';
|
||||
const dataStoreAddress = '0xFD70de6b91282D8017aA4E741e9Ae325CAb992d8';
|
||||
|
||||
const getAccountPositionsAbi = v2ReaderAbi.find(f => f.name === 'getAccountPositions');
|
||||
|
||||
const getMarketsAbi = v2ReaderAbi.find(f => f.name === 'getMarkets');
|
||||
const markets = await api.call({
|
||||
abi: getMarketsAbi,
|
||||
abi: v2ReaderAbi.getMarkets,
|
||||
target: v2ReaderAddress,
|
||||
params: [dataStoreAddress, 0, 32]
|
||||
});
|
||||
})
|
||||
|
||||
const marketToTokenMap = {};
|
||||
for (const market of markets) {
|
||||
marketToTokenMap[market[0]] = market[1];
|
||||
}
|
||||
for (const vault of vaults) {
|
||||
await api.sumTokens({
|
||||
tokensAndOwners: [
|
||||
// Wallet
|
||||
[ADDRESSES.arbitrum.USDC, vault],
|
||||
[ADDRESSES.arbitrum.USDT, vault],
|
||||
[ADDRESSES.arbitrum.USDC_CIRCLE, vault],
|
||||
[ADDRESSES.arbitrum.WETH, vault],
|
||||
[ADDRESSES.null, vault],
|
||||
[ADDRESSES.arbitrum.WBTC, vault],
|
||||
// GMXv2 Earn
|
||||
[addresses.gmWeth, vault],
|
||||
[addresses.gmBtc, vault],
|
||||
// Aave
|
||||
[addresses.aaveEthAToken, vault],
|
||||
[addresses.aaveBtcAToken, vault],
|
||||
[addresses.aaveUsdcAToken, vault],
|
||||
[addresses.aaveEthDebtToken, vault],
|
||||
[addresses.aaveBtcDebtToken, vault],
|
||||
[addresses.aaveUsdcDebtToken, vault],
|
||||
]
|
||||
});
|
||||
// GMXv2 Trade
|
||||
const positions = await api.call({
|
||||
abi: getAccountPositionsAbi,
|
||||
target: v2ReaderAddress,
|
||||
params: [dataStoreAddress, vault, 0, 999999999999]
|
||||
});
|
||||
for (const pos of positions) {
|
||||
// collateral
|
||||
await api.add(pos.addresses.collateralToken, pos.numbers.collateralAmount);
|
||||
// pnl = sizeInTokens * tokenPrice - sizeInUsd
|
||||
await api.add(marketToTokenMap[pos.addresses.market], pos.numbers.sizeInTokens);
|
||||
await api.add(ADDRESSES.arbitrum.USDC_CIRCLE, -pos.numbers.sizeInUsd * 1e-24);
|
||||
}
|
||||
await api.sumTokens({
|
||||
tokens: [
|
||||
// Wallet
|
||||
ADDRESSES.arbitrum.USDC,
|
||||
ADDRESSES.arbitrum.USDT,
|
||||
ADDRESSES.arbitrum.USDC_CIRCLE,
|
||||
ADDRESSES.arbitrum.WETH,
|
||||
ADDRESSES.null,
|
||||
ADDRESSES.arbitrum.WBTC,
|
||||
// GMXv2 Earn
|
||||
addresses.gmWeth,
|
||||
addresses.gmBtc,
|
||||
// Aave
|
||||
addresses.aaveEthAToken,
|
||||
addresses.aaveBtcAToken,
|
||||
addresses.aaveUsdcAToken,
|
||||
addresses.aaveEthDebtToken,
|
||||
addresses.aaveBtcDebtToken,
|
||||
addresses.aaveUsdcDebtToken,
|
||||
],
|
||||
owners: vaults
|
||||
})
|
||||
|
||||
// GMXv2 Trade
|
||||
const calls = vaults.map(vault => ({ params: [dataStoreAddress, vault, 0, 999999999999], }))
|
||||
const positions = await api.multiCall({
|
||||
abi: v2ReaderAbi.getAccountPositions,
|
||||
target: v2ReaderAddress,
|
||||
calls,
|
||||
});
|
||||
for (const pos of positions) {
|
||||
if (!pos || !pos.addresses || !pos.numbers) continue;
|
||||
// collateral
|
||||
api.add(pos.addresses.collateralToken, pos.numbers.collateralAmount);
|
||||
// pnl = sizeInTokens * tokenPrice - sizeInUsd
|
||||
api.add(marketToTokenMap[pos.addresses.market], pos.numbers.sizeInTokens);
|
||||
api.add(ADDRESSES.arbitrum.USDC_CIRCLE, -pos.numbers.sizeInUsd * 1e-24);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,182 @@
|
||||
const sdk = require('@defillama/sdk')
|
||||
const { Connection, PublicKey } = require('@solana/web3.js')
|
||||
const { PublicKey } = require('@solana/web3.js')
|
||||
const { Program, AnchorProvider, BN } = require("@coral-xyz/anchor");
|
||||
const { getConnection, getProvider, decodeAccount } = require('../helper/solana');
|
||||
const loopscaleIdl = require('./loopscale.json');
|
||||
const { getConnection, } = require('../helper/solana');
|
||||
const loopscaleIdl = {
|
||||
"address": "1oopBoJG58DgkUVKkEzKgyG9dvRmpgeEm1AVjoHkF78",
|
||||
"metadata": {"name": "loopscale", "version": "0.1.0", "spec": "0.1.0", "description": "Created with Anchor"},
|
||||
"instructions": [],
|
||||
"accounts": [
|
||||
{"name": "Loan", "discriminator": [20, 195, 70, 117, 165, 227, 182, 1]},
|
||||
{"name": "Strategy", "discriminator": [174, 110, 39, 119, 82, 106, 169, 102]}
|
||||
],
|
||||
"events": [],
|
||||
"errors": [],
|
||||
"types": [
|
||||
{
|
||||
"name": "Loan",
|
||||
"serialization": "bytemuck",
|
||||
"repr": {"kind": "c", "packed": true},
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{"name": "version", "type": "u8"},
|
||||
{"name": "bump", "type": "u8"},
|
||||
{"name": "loan_status", "type": "u8"},
|
||||
{"name": "borrower", "type": "pubkey"},
|
||||
{"name": "nonce", "type": "u64"},
|
||||
{"name": "start_time", "type": {"defined": {"name": "PodU64"}}},
|
||||
{"name": "ledgers", "type": {"array": [{"defined": {"name": "Ledger"}}, 5]}},
|
||||
{"name": "collateral", "type": {"array": [{"defined": {"name": "CollateralData"}}, 5]}}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "PodU64",
|
||||
"docs": ["Represents a 64-bit unsigned integer stored as bytes (little-endian)"],
|
||||
"repr": {"kind": "transparent"},
|
||||
"type": {"kind": "struct", "fields": [{"array": ["u8", 8]}]}
|
||||
},
|
||||
{
|
||||
"name": "Ledger",
|
||||
"serialization": "bytemuck",
|
||||
"repr": {"kind": "c", "packed": true},
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{"name": "status", "type": "u8"},
|
||||
{"name": "strategy", "type": "pubkey"},
|
||||
{"name": "principal_mint", "type": "pubkey"},
|
||||
{"name": "market_information", "type": "pubkey"},
|
||||
{"name": "principal_due", "type": {"defined": {"name": "PodU64"}}},
|
||||
{"name": "principal_repaid", "type": {"defined": {"name": "PodU64"}}},
|
||||
{"name": "interest_due", "type": {"defined": {"name": "PodU64"}}},
|
||||
{"name": "interest_repaid", "type": {"defined": {"name": "PodU64"}}},
|
||||
{"name": "duration", "type": {"defined": {"name": "Duration"}}},
|
||||
{"name": "interest_per_second", "type": {"defined": {"name": "PodDecimal"}}},
|
||||
{"name": "start_time", "type": {"defined": {"name": "PodU64"}}},
|
||||
{"name": "end_time", "type": {"defined": {"name": "PodU64"}}},
|
||||
{"name": "apy", "type": {"defined": {"name": "PodU64CBPS"}}}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Duration",
|
||||
"serialization": "bytemuck",
|
||||
"repr": {"kind": "c", "packed": true},
|
||||
"type": {"kind": "struct", "fields": [{"name": "duration", "type": {"defined": {"name": "PodU32"}}}, {"name": "duration_type", "type": "u8"}]}
|
||||
},
|
||||
{
|
||||
"name": "PodU32",
|
||||
"docs": ["Represents a 32-bit unsigned integer stored as bytes (little-endian)"],
|
||||
"repr": {"kind": "transparent"},
|
||||
"type": {"kind": "struct", "fields": [{"array": ["u8", 4]}]}
|
||||
},
|
||||
{
|
||||
"name": "PodDecimal",
|
||||
"docs": [
|
||||
"this is the scaled representation of a whole number. The whole number is scaled by 10^18 to avoid floating point errors when performing arithmetic operations."
|
||||
],
|
||||
"repr": {"kind": "c"},
|
||||
"type": {"kind": "struct", "fields": [{"array": ["u8", 24]}]}
|
||||
},
|
||||
{
|
||||
"name": "PodU64CBPS",
|
||||
"docs": ["helper type to store u64 cbps values"],
|
||||
"repr": {"kind": "c"},
|
||||
"type": {"kind": "struct", "fields": [{"array": ["u8", 8]}]}
|
||||
},
|
||||
{
|
||||
"name": "CollateralData",
|
||||
"serialization": "bytemuck",
|
||||
"repr": {"kind": "c", "packed": true},
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{"name": "asset_mint", "type": "pubkey"},
|
||||
{"name": "amount", "type": {"defined": {"name": "PodU64"}}},
|
||||
{"name": "asset_type", "type": "u8"},
|
||||
{"name": "asset_identifier", "type": "pubkey"}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Strategy",
|
||||
"serialization": "bytemuck",
|
||||
"repr": {"kind": "c", "packed": true},
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{"name": "version", "type": "u8"},
|
||||
{"name": "nonce", "type": "pubkey"},
|
||||
{"name": "bump", "type": "u8"},
|
||||
{"name": "principal_mint", "type": "pubkey"},
|
||||
{"name": "lender", "type": "pubkey"},
|
||||
{"name": "originations_enabled", "type": {"defined": {"name": "PodBool"}}},
|
||||
{"name": "external_yield_source", "type": "u8"},
|
||||
{"name": "interest_per_second", "type": {"defined": {"name": "PodDecimal"}}},
|
||||
{
|
||||
"name": "last_accrued_timestamp",
|
||||
"docs": ["timestamp interest per second's interest was last accrued"],
|
||||
"type": {"defined": {"name": "PodU64"}}
|
||||
},
|
||||
{
|
||||
"name": "liquidity_buffer",
|
||||
"docs": ["the is the amount of liquidity % that always needs to be in the strategy"],
|
||||
"type": {"defined": {"name": "PodU64CBPS"}}
|
||||
},
|
||||
{"name": "token_balance", "docs": ["amount of principal in the strategy"], "type": {"defined": {"name": "PodU64"}}},
|
||||
{
|
||||
"name": "interest_fee",
|
||||
"docs": ["this is the fee charged by and accrued to the manager on the interest accrued via external yield and loans"],
|
||||
"type": {"defined": {"name": "PodU64CBPS"}}
|
||||
},
|
||||
{
|
||||
"name": "principal_fee",
|
||||
"docs": ["this is the fee charged by and accrued to the manager on the origination fee"],
|
||||
"type": {"defined": {"name": "PodU64CBPS"}}
|
||||
},
|
||||
{"name": "origination_fee", "docs": ["fee charged on origination of new loans"], "type": {"defined": {"name": "PodU64CBPS"}}},
|
||||
{"name": "origination_cap", "docs": ["the maximum size of a loan that can be originated"], "type": {"defined": {"name": "PodU64"}}},
|
||||
{
|
||||
"name": "external_yield_amount",
|
||||
"docs": ["this is the amount of principal currently in external yield. has to always be updated on any new nav action"],
|
||||
"type": {"defined": {"name": "PodU64"}}
|
||||
},
|
||||
{
|
||||
"name": "current_deployed_amount",
|
||||
"docs": ["this is the amount of principal currently deployed in loans"],
|
||||
"type": {"defined": {"name": "PodU64"}}
|
||||
},
|
||||
{
|
||||
"name": "outstanding_interest_amount",
|
||||
"docs": ["this is the interest that has not been repaid yet but accrued"],
|
||||
"type": {"defined": {"name": "PodU64"}}
|
||||
},
|
||||
{"name": "fee_claimable", "docs": ["this is the amount that has accrued to the manager"], "type": {"defined": {"name": "PodU64"}}},
|
||||
{"name": "cumulative_principal_originated", "type": {"defined": {"name": "PodU128"}}},
|
||||
{"name": "cumulative_interest_accrued", "type": {"defined": {"name": "PodU128"}}},
|
||||
{"name": "cumulative_loan_count", "type": {"defined": {"name": "PodU64"}}},
|
||||
{"name": "active_loan_count", "type": {"defined": {"name": "PodU64"}}},
|
||||
{"name": "market_information", "type": "pubkey"},
|
||||
{"name": "collateral_map", "type": {"array": [{"array": [{"defined": {"name": "PodU64"}}, 5]}, 200]}},
|
||||
{"name": "external_yield_accounts", "type": {"defined": {"name": "ExternalYieldAccounts"}}}
|
||||
]
|
||||
}
|
||||
},
|
||||
{"name": "PodBool", "docs": ["Represents a bool stored as a byte"], "repr": {"kind": "transparent"}, "type": {"kind": "struct", "fields": ["u8"]}},
|
||||
{
|
||||
"name": "PodU128",
|
||||
"docs": ["Represents a 128-bit unsigned integer stored as bytes (little-endian)"],
|
||||
"repr": {"kind": "c"},
|
||||
"type": {"kind": "struct", "fields": [{"array": ["u8", 16]}]}
|
||||
},
|
||||
{
|
||||
"name": "ExternalYieldAccounts",
|
||||
"repr": {"kind": "c", "packed": true},
|
||||
"type": {"kind": "struct", "fields": [{"name": "external_yield_account", "type": "pubkey"}, {"name": "external_yield_vault", "type": "pubkey"}]}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const endpoint = 'https://loopscale-pricing-adapters-109615290061.europe-west2.run.app/decompile_mints'
|
||||
|
||||
@@ -154,5 +328,5 @@ module.exports = {
|
||||
timetravel: false,
|
||||
methodology:
|
||||
'TVL is calculated by summing up lending deposits and supplied collateral. Borrowed tokens are included.',
|
||||
solana: { tvl, borrowed },
|
||||
solana: { tvl, borrowed, },
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
75
utils/scripts/sortTopFilesByLines.js
Normal file
75
utils/scripts/sortTopFilesByLines.js
Normal file
@@ -0,0 +1,75 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function countLines(filePath) {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
return content.split('\n').length;
|
||||
} catch (error) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function getAllFiles(dirPath, filesList = []) {
|
||||
try {
|
||||
const files = fs.readdirSync(dirPath);
|
||||
|
||||
files.forEach(file => {
|
||||
const filePath = path.join(dirPath, file);
|
||||
const stat = fs.statSync(filePath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
if (!blacklistedFolders.has(file))
|
||||
getAllFiles(filePath, filesList);
|
||||
} else {
|
||||
filesList.push(filePath);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Error reading directory ${dirPath}:`, error.message);
|
||||
}
|
||||
|
||||
return filesList;
|
||||
}
|
||||
|
||||
const blacklistedFolders = new Set(['node_modules'])
|
||||
|
||||
function main() {
|
||||
const projectsDir = path.join(__dirname, '../../projects');
|
||||
|
||||
if (!fs.existsSync(projectsDir)) {
|
||||
console.error('Projects folder not found!');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Scanning files...');
|
||||
const allFiles = getAllFiles(projectsDir);
|
||||
|
||||
console.log('Counting lines...');
|
||||
const filesWithLines = allFiles.map(filePath => ({
|
||||
path: path.relative(projectsDir, filePath),
|
||||
lines: countLines(filePath)
|
||||
}));
|
||||
|
||||
// Sort by line count (descending) and take top 100
|
||||
const top100 = filesWithLines
|
||||
.sort((a, b) => b.lines - a.lines)
|
||||
.slice(0, 100);
|
||||
|
||||
// Print table
|
||||
console.log('\nTop 100 Files by Line Count:');
|
||||
console.log('─'.repeat(80));
|
||||
console.log('File Path'.padEnd(60) + 'Lines');
|
||||
console.log('─'.repeat(80));
|
||||
|
||||
top100.forEach((file, index) => {
|
||||
const truncatedPath = file.path.length > 58 ?
|
||||
'...' + file.path.slice(-55) : file.path;
|
||||
console.log(`${truncatedPath.padEnd(60)}${file.lines}`);
|
||||
});
|
||||
|
||||
console.log('─'.repeat(80));
|
||||
console.log(`Total files scanned: ${allFiles.length}`);
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user