@net-protocol/score 0.1.8 → 0.1.10
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/README.md +30 -0
- package/dist/index.d.mts +107 -28
- package/dist/index.d.ts +107 -28
- package/dist/index.js +474 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +475 -39
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +3 -1
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +3 -1
- package/dist/react.mjs.map +1 -1
- package/dist/{scoreKeyUtils-BjMpyhyX.d.mts → scoreKeyUtils-BQl5oCSc.d.mts} +1 -1
- package/dist/{scoreKeyUtils-BjMpyhyX.d.ts → scoreKeyUtils-BQl5oCSc.d.ts} +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readContract } from 'viem/actions';
|
|
2
|
-
import { getPublicClient, getBaseDataSuffix } from '@net-protocol/core';
|
|
2
|
+
import { getPublicClient, getBaseDataSuffix, NetClient } from '@net-protocol/core';
|
|
3
3
|
import { decodeAbiParameters, keccak256, encodePacked, getAddress, encodeAbiParameters, isAddressEqual } from 'viem';
|
|
4
|
-
import { getStorageKeyBytes } from '@net-protocol/storage';
|
|
4
|
+
import { getStorageKeyBytes, STORAGE_CONTRACT } from '@net-protocol/storage';
|
|
5
5
|
|
|
6
6
|
// src/client/ScoreClient.ts
|
|
7
7
|
|
|
@@ -2482,6 +2482,44 @@ var user_upvote_default = [
|
|
|
2482
2482
|
{ type: "error", name: "ZeroUpvotes", inputs: [] }
|
|
2483
2483
|
];
|
|
2484
2484
|
|
|
2485
|
+
// src/abis/erc20-bulk-info-helper.json
|
|
2486
|
+
var erc20_bulk_info_helper_default = [
|
|
2487
|
+
{
|
|
2488
|
+
type: "function",
|
|
2489
|
+
name: "getTokenInfo",
|
|
2490
|
+
inputs: [
|
|
2491
|
+
{
|
|
2492
|
+
name: "tokenAddresses",
|
|
2493
|
+
type: "address[]",
|
|
2494
|
+
internalType: "address[]"
|
|
2495
|
+
}
|
|
2496
|
+
],
|
|
2497
|
+
outputs: [
|
|
2498
|
+
{
|
|
2499
|
+
name: "tokenInfos",
|
|
2500
|
+
type: "tuple[]",
|
|
2501
|
+
internalType: "struct ERC20BulkInfoHelper.TokenInfo[]",
|
|
2502
|
+
components: [
|
|
2503
|
+
{ name: "name", type: "string", internalType: "string" },
|
|
2504
|
+
{ name: "symbol", type: "string", internalType: "string" },
|
|
2505
|
+
{ name: "decimals", type: "uint8", internalType: "uint8" },
|
|
2506
|
+
{
|
|
2507
|
+
name: "totalSupply",
|
|
2508
|
+
type: "uint256",
|
|
2509
|
+
internalType: "uint256"
|
|
2510
|
+
},
|
|
2511
|
+
{
|
|
2512
|
+
name: "burnedTokens",
|
|
2513
|
+
type: "uint256",
|
|
2514
|
+
internalType: "uint256"
|
|
2515
|
+
}
|
|
2516
|
+
]
|
|
2517
|
+
}
|
|
2518
|
+
],
|
|
2519
|
+
stateMutability: "view"
|
|
2520
|
+
}
|
|
2521
|
+
];
|
|
2522
|
+
|
|
2485
2523
|
// src/constants.ts
|
|
2486
2524
|
var SCORE_CONTRACT = {
|
|
2487
2525
|
address: "0x0000000fa09b022e5616e5a173b4b67fa2fbcf28",
|
|
@@ -2526,8 +2564,10 @@ var MULTI_VERSION_UNISWAP_POOL_INFO_RETRIEVER = {
|
|
|
2526
2564
|
var WETH_BY_CHAIN = {
|
|
2527
2565
|
8453: "0x4200000000000000000000000000000000000006",
|
|
2528
2566
|
// Base (L2 predeploy)
|
|
2529
|
-
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
|
2567
|
+
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
2530
2568
|
// Ethereum mainnet
|
|
2569
|
+
4663: "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73"
|
|
2570
|
+
// Robinhood Chain (non-standard WETH; not the OP predeploy)
|
|
2531
2571
|
};
|
|
2532
2572
|
function getWethAddress(chainId) {
|
|
2533
2573
|
const addr = WETH_BY_CHAIN[chainId];
|
|
@@ -2542,6 +2582,10 @@ var USER_UPVOTE_CONTRACT = {
|
|
|
2542
2582
|
address: "0xa4bc2c63dd0157692fd5f409389e5032e37d8895",
|
|
2543
2583
|
abi: user_upvote_default
|
|
2544
2584
|
};
|
|
2585
|
+
var ERC20_BULK_INFO_HELPER_CONTRACT = {
|
|
2586
|
+
address: "0x00000051809cbfacdf7d08ada813836822b880a2",
|
|
2587
|
+
abi: erc20_bulk_info_helper_default
|
|
2588
|
+
};
|
|
2545
2589
|
var encodeUpvoteKey = (tokenAddress) => {
|
|
2546
2590
|
return `0x${BigInt(`0x${tokenAddress.slice(2)}`).toString(16).padStart(64, "0")}`;
|
|
2547
2591
|
};
|
|
@@ -3207,41 +3251,6 @@ var UserUpvoteClient = class {
|
|
|
3207
3251
|
return hash;
|
|
3208
3252
|
}
|
|
3209
3253
|
};
|
|
3210
|
-
var encodePoolKey = (poolKey) => {
|
|
3211
|
-
if (!poolKey || !isValidPoolKey2(poolKey)) {
|
|
3212
|
-
return "0x";
|
|
3213
|
-
}
|
|
3214
|
-
try {
|
|
3215
|
-
return encodeAbiParameters(
|
|
3216
|
-
[
|
|
3217
|
-
{
|
|
3218
|
-
type: "tuple",
|
|
3219
|
-
components: [
|
|
3220
|
-
{ name: "currency0", type: "address" },
|
|
3221
|
-
{ name: "currency1", type: "address" },
|
|
3222
|
-
{ name: "fee", type: "uint24" },
|
|
3223
|
-
{ name: "tickSpacing", type: "int24" },
|
|
3224
|
-
{ name: "hooks", type: "address" }
|
|
3225
|
-
]
|
|
3226
|
-
}
|
|
3227
|
-
],
|
|
3228
|
-
[
|
|
3229
|
-
{
|
|
3230
|
-
currency0: poolKey.currency0,
|
|
3231
|
-
currency1: poolKey.currency1,
|
|
3232
|
-
fee: poolKey.fee,
|
|
3233
|
-
tickSpacing: poolKey.tickSpacing,
|
|
3234
|
-
hooks: poolKey.hooks
|
|
3235
|
-
}
|
|
3236
|
-
]
|
|
3237
|
-
);
|
|
3238
|
-
} catch {
|
|
3239
|
-
return "0x";
|
|
3240
|
-
}
|
|
3241
|
-
};
|
|
3242
|
-
function isValidPoolKey2(poolKey) {
|
|
3243
|
-
return poolKey.fee !== void 0 || poolKey.tickSpacing !== void 0 || poolKey.currency0 !== void 0;
|
|
3244
|
-
}
|
|
3245
3254
|
var V3_V4_FEE_TIERS = [500, 3e3, 1e4, 12e3, 8388608];
|
|
3246
3255
|
var V4_TICK_SPACINGS = [200];
|
|
3247
3256
|
var V4_HOOKS = [
|
|
@@ -3595,6 +3604,433 @@ async function discoverTokenPool({
|
|
|
3595
3604
|
return results[0] ?? null;
|
|
3596
3605
|
}
|
|
3597
3606
|
|
|
3598
|
-
|
|
3607
|
+
// src/ranking/getTokenRankings.ts
|
|
3608
|
+
var DEFAULT_MESSAGE_SCAN_WINDOW = 150;
|
|
3609
|
+
var DEFAULT_MAX_TOKENS = 50;
|
|
3610
|
+
var DEFAULT_MIN_UPVOTES = 500;
|
|
3611
|
+
var DEFAULT_MIN_MARKET_CAP = 4e4;
|
|
3612
|
+
var DEFAULT_RECENCY_HOURS = 48;
|
|
3613
|
+
var USDC_ADDRESS_BY_CHAIN = {
|
|
3614
|
+
8453: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
|
|
3615
|
+
};
|
|
3616
|
+
var ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
3617
|
+
async function getTokenRankings(options) {
|
|
3618
|
+
const {
|
|
3619
|
+
chainId,
|
|
3620
|
+
sort = "trending",
|
|
3621
|
+
maxTokens = DEFAULT_MAX_TOKENS,
|
|
3622
|
+
messageScanWindow = DEFAULT_MESSAGE_SCAN_WINDOW,
|
|
3623
|
+
rpcUrl
|
|
3624
|
+
} = options;
|
|
3625
|
+
validateChainSupported(chainId);
|
|
3626
|
+
const minUpvotes = options.thresholds?.minUpvotes ?? DEFAULT_MIN_UPVOTES;
|
|
3627
|
+
const minMarketCap = options.thresholds?.minMarketCap ?? DEFAULT_MIN_MARKET_CAP;
|
|
3628
|
+
const recencyHours = options.thresholds?.recencyHours ?? DEFAULT_RECENCY_HOURS;
|
|
3629
|
+
const nowSec = Date.now() / 1e3;
|
|
3630
|
+
const rpcOverride = rpcUrl ? { rpcUrls: Array.isArray(rpcUrl) ? rpcUrl : [rpcUrl] } : void 0;
|
|
3631
|
+
const publicClient = getPublicClient({ chainId, rpcUrl });
|
|
3632
|
+
const netClient = new NetClient({ chainId, overrides: rpcOverride });
|
|
3633
|
+
const messageGroups = await fetchUpvoteMessages({
|
|
3634
|
+
netClient,
|
|
3635
|
+
messageScanWindow
|
|
3636
|
+
});
|
|
3637
|
+
const storageBlobByKey = await fetchStrategyStorage({
|
|
3638
|
+
publicClient,
|
|
3639
|
+
messageGroups
|
|
3640
|
+
});
|
|
3641
|
+
const wethAddress = getWethAddress(chainId);
|
|
3642
|
+
const { tokenAddresses, latestUpvoteTimestamps } = aggregateAndRank({
|
|
3643
|
+
messageGroups,
|
|
3644
|
+
storageBlobByKey,
|
|
3645
|
+
sort,
|
|
3646
|
+
maxTokens,
|
|
3647
|
+
excludeAddresses: [wethAddress.toLowerCase()],
|
|
3648
|
+
nowSec
|
|
3649
|
+
});
|
|
3650
|
+
if (tokenAddresses.length === 0) return [];
|
|
3651
|
+
const usdcAddress = USDC_ADDRESS_BY_CHAIN[chainId];
|
|
3652
|
+
const pairs = [
|
|
3653
|
+
...tokenAddresses.map((tokenAddress) => ({
|
|
3654
|
+
tokenAddress,
|
|
3655
|
+
baseTokenAddress: wethAddress
|
|
3656
|
+
})),
|
|
3657
|
+
...usdcAddress ? [{ tokenAddress: wethAddress, baseTokenAddress: usdcAddress }] : []
|
|
3658
|
+
];
|
|
3659
|
+
const [tokenInfos, pools, upvoteCounts] = await Promise.all([
|
|
3660
|
+
fetchBulkErc20Info({ publicClient, addresses: tokenAddresses }),
|
|
3661
|
+
discoverPools({ publicClient, pairs, chainId }),
|
|
3662
|
+
fetchAggregateUpvotes({ publicClient, tokenAddresses })
|
|
3663
|
+
]);
|
|
3664
|
+
if (tokenInfos.length !== tokenAddresses.length) {
|
|
3665
|
+
throw new Error(
|
|
3666
|
+
`ERC20 bulk info returned ${tokenInfos.length} entries for ${tokenAddresses.length} addresses`
|
|
3667
|
+
);
|
|
3668
|
+
}
|
|
3669
|
+
if (upvoteCounts.length !== tokenAddresses.length) {
|
|
3670
|
+
throw new Error(
|
|
3671
|
+
`getUpvotesWithLegacy returned ${upvoteCounts.length} entries for ${tokenAddresses.length} addresses`
|
|
3672
|
+
);
|
|
3673
|
+
}
|
|
3674
|
+
return composeAndFilter({
|
|
3675
|
+
tokenAddresses,
|
|
3676
|
+
tokenInfos,
|
|
3677
|
+
pools,
|
|
3678
|
+
upvoteCounts,
|
|
3679
|
+
latestUpvoteTimestamps,
|
|
3680
|
+
wethAddress,
|
|
3681
|
+
usdcAddress,
|
|
3682
|
+
sort,
|
|
3683
|
+
maxTokens,
|
|
3684
|
+
minUpvotes,
|
|
3685
|
+
minMarketCap,
|
|
3686
|
+
recencyHours,
|
|
3687
|
+
nowSec
|
|
3688
|
+
});
|
|
3689
|
+
}
|
|
3690
|
+
function validateChainSupported(chainId) {
|
|
3691
|
+
if (!SUPPORTED_SCORE_CHAINS.includes(chainId)) {
|
|
3692
|
+
throw new Error(
|
|
3693
|
+
`getTokenRankings: chainId ${chainId} is not supported. Supported chains: ${SUPPORTED_SCORE_CHAINS.join(", ")}`
|
|
3694
|
+
);
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
async function fetchUpvoteMessages({
|
|
3698
|
+
netClient,
|
|
3699
|
+
messageScanWindow
|
|
3700
|
+
}) {
|
|
3701
|
+
const legacyFilter = {
|
|
3702
|
+
appAddress: LEGACY_UPVOTE_V1_ADDRESS,
|
|
3703
|
+
topic: "t"
|
|
3704
|
+
};
|
|
3705
|
+
const strategyFilters = [
|
|
3706
|
+
UNIV234_POOLS_STRATEGY.address,
|
|
3707
|
+
PURE_ALPHA_STRATEGY.address,
|
|
3708
|
+
DYNAMIC_SPLIT_STRATEGY.address
|
|
3709
|
+
].map((stratAddr) => ({
|
|
3710
|
+
appAddress: SCORE_CONTRACT.address,
|
|
3711
|
+
topic: `t${stratAddr.toLowerCase()}`
|
|
3712
|
+
}));
|
|
3713
|
+
const [legacyCount, ...strategyCounts] = await Promise.all([
|
|
3714
|
+
netClient.getMessageCount({ filter: legacyFilter }),
|
|
3715
|
+
...strategyFilters.map((filter) => netClient.getMessageCount({ filter }))
|
|
3716
|
+
]);
|
|
3717
|
+
const sliceRange = (count) => ({
|
|
3718
|
+
startIndex: Math.max(0, count - messageScanWindow),
|
|
3719
|
+
endIndex: count
|
|
3720
|
+
});
|
|
3721
|
+
const [legacy, strategy1, strategy2, strategy3] = await Promise.all([
|
|
3722
|
+
legacyCount > 0 ? netClient.getMessagesBatch({
|
|
3723
|
+
filter: legacyFilter,
|
|
3724
|
+
...sliceRange(legacyCount)
|
|
3725
|
+
}) : Promise.resolve([]),
|
|
3726
|
+
...strategyFilters.map(
|
|
3727
|
+
(filter, i) => strategyCounts[i] > 0 ? netClient.getMessagesBatch({
|
|
3728
|
+
filter,
|
|
3729
|
+
...sliceRange(strategyCounts[i])
|
|
3730
|
+
}) : Promise.resolve([])
|
|
3731
|
+
)
|
|
3732
|
+
]);
|
|
3733
|
+
return { legacy, strategy1, strategy2, strategy3 };
|
|
3734
|
+
}
|
|
3735
|
+
async function fetchStrategyStorage({
|
|
3736
|
+
publicClient,
|
|
3737
|
+
messageGroups
|
|
3738
|
+
}) {
|
|
3739
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3740
|
+
const keys = [];
|
|
3741
|
+
for (const msg of [
|
|
3742
|
+
...messageGroups.strategy1,
|
|
3743
|
+
...messageGroups.strategy2,
|
|
3744
|
+
...messageGroups.strategy3
|
|
3745
|
+
]) {
|
|
3746
|
+
if (!msg.data || !msg.data.startsWith("0x")) continue;
|
|
3747
|
+
const key = msg.data;
|
|
3748
|
+
if (seen.has(key)) continue;
|
|
3749
|
+
seen.add(key);
|
|
3750
|
+
keys.push({ key, operator: SCORE_CONTRACT.address });
|
|
3751
|
+
}
|
|
3752
|
+
if (keys.length === 0) return /* @__PURE__ */ new Map();
|
|
3753
|
+
const results = await readContract(publicClient, {
|
|
3754
|
+
address: STORAGE_CONTRACT.address,
|
|
3755
|
+
abi: STORAGE_CONTRACT.abi,
|
|
3756
|
+
functionName: "bulkGet",
|
|
3757
|
+
args: [keys]
|
|
3758
|
+
});
|
|
3759
|
+
return buildStorageMapFromBulkGetResults(results, keys);
|
|
3760
|
+
}
|
|
3761
|
+
function buildStorageMapFromBulkGetResults(results, keys) {
|
|
3762
|
+
if (results.length !== keys.length) {
|
|
3763
|
+
throw new Error(
|
|
3764
|
+
`bulkGet returned ${results.length} entries for ${keys.length} keys`
|
|
3765
|
+
);
|
|
3766
|
+
}
|
|
3767
|
+
const map = /* @__PURE__ */ new Map();
|
|
3768
|
+
results.forEach((item, idx) => {
|
|
3769
|
+
const value = item?.value;
|
|
3770
|
+
if (value && value !== "0x") {
|
|
3771
|
+
map.set(keys[idx].key, value);
|
|
3772
|
+
}
|
|
3773
|
+
});
|
|
3774
|
+
return map;
|
|
3775
|
+
}
|
|
3776
|
+
function aggregateAndRank({
|
|
3777
|
+
messageGroups,
|
|
3778
|
+
storageBlobByKey,
|
|
3779
|
+
sort,
|
|
3780
|
+
maxTokens,
|
|
3781
|
+
excludeAddresses = [],
|
|
3782
|
+
nowSec
|
|
3783
|
+
}) {
|
|
3784
|
+
const tokenUpvoteEvents = /* @__PURE__ */ new Map();
|
|
3785
|
+
const excludeSet = new Set(excludeAddresses.map((a) => a.toLowerCase()));
|
|
3786
|
+
const addEvent = (tokenAddress, timestamp, count) => {
|
|
3787
|
+
if (!ADDRESS_RE.test(tokenAddress)) return;
|
|
3788
|
+
const lower = tokenAddress.toLowerCase();
|
|
3789
|
+
if (lower === NULL_ADDRESS || excludeSet.has(lower)) return;
|
|
3790
|
+
if (!Number.isFinite(timestamp) || !Number.isFinite(count)) return;
|
|
3791
|
+
const events = tokenUpvoteEvents.get(lower) ?? [];
|
|
3792
|
+
events.push({ timestamp, count });
|
|
3793
|
+
tokenUpvoteEvents.set(lower, events);
|
|
3794
|
+
};
|
|
3795
|
+
for (const msg of messageGroups.legacy) {
|
|
3796
|
+
if (msg.topic !== "t" || !msg.text) continue;
|
|
3797
|
+
let count = 1;
|
|
3798
|
+
if (msg.data && msg.data.startsWith("0x")) {
|
|
3799
|
+
try {
|
|
3800
|
+
const [votes] = decodeAbiParameters(
|
|
3801
|
+
[{ type: "uint256" }],
|
|
3802
|
+
msg.data
|
|
3803
|
+
);
|
|
3804
|
+
count = Number(votes);
|
|
3805
|
+
} catch {
|
|
3806
|
+
count = 1;
|
|
3807
|
+
}
|
|
3808
|
+
}
|
|
3809
|
+
addEvent(msg.text, Number(msg.timestamp), count);
|
|
3810
|
+
}
|
|
3811
|
+
for (const msg of [
|
|
3812
|
+
...messageGroups.strategy1,
|
|
3813
|
+
...messageGroups.strategy2,
|
|
3814
|
+
...messageGroups.strategy3
|
|
3815
|
+
]) {
|
|
3816
|
+
if (!msg.topic.startsWith("t") || !msg.data || !msg.data.startsWith("0x")) {
|
|
3817
|
+
continue;
|
|
3818
|
+
}
|
|
3819
|
+
const blob = storageBlobByKey.get(msg.data);
|
|
3820
|
+
if (!blob) continue;
|
|
3821
|
+
const decoded = decodeUpvoteStorageBlob(blob);
|
|
3822
|
+
if (!decoded || !decoded.scoreKey) continue;
|
|
3823
|
+
const tokenAddress = extractTokenAddressFromScoreKey(decoded.scoreKey);
|
|
3824
|
+
if (!tokenAddress) continue;
|
|
3825
|
+
addEvent(tokenAddress, Number(msg.timestamp), decoded.scoreDelta);
|
|
3826
|
+
}
|
|
3827
|
+
const timeWeight = (ts) => Math.exp(-0.1 * ((nowSec - ts) / 3600));
|
|
3828
|
+
const latestUpvoteTimestamps = /* @__PURE__ */ new Map();
|
|
3829
|
+
for (const [addr, events] of tokenUpvoteEvents) {
|
|
3830
|
+
let latest = events[0].timestamp;
|
|
3831
|
+
for (const e of events) if (e.timestamp > latest) latest = e.timestamp;
|
|
3832
|
+
latestUpvoteTimestamps.set(addr, latest);
|
|
3833
|
+
}
|
|
3834
|
+
let ordered;
|
|
3835
|
+
if (sort === "top") {
|
|
3836
|
+
ordered = Array.from(tokenUpvoteEvents.keys());
|
|
3837
|
+
} else {
|
|
3838
|
+
const scores = /* @__PURE__ */ new Map();
|
|
3839
|
+
for (const [addr, events] of tokenUpvoteEvents) {
|
|
3840
|
+
if (sort === "recent") {
|
|
3841
|
+
scores.set(addr, latestUpvoteTimestamps.get(addr) ?? 0);
|
|
3842
|
+
} else {
|
|
3843
|
+
const score = events.reduce(
|
|
3844
|
+
(total, e) => total + e.count * timeWeight(e.timestamp),
|
|
3845
|
+
0
|
|
3846
|
+
);
|
|
3847
|
+
scores.set(addr, score);
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
ordered = Array.from(scores.entries()).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([address]) => address);
|
|
3851
|
+
}
|
|
3852
|
+
const fetchLimit = Math.max(maxTokens * 3, 30);
|
|
3853
|
+
return {
|
|
3854
|
+
tokenAddresses: ordered.slice(0, fetchLimit),
|
|
3855
|
+
latestUpvoteTimestamps
|
|
3856
|
+
};
|
|
3857
|
+
}
|
|
3858
|
+
async function fetchBulkErc20Info({
|
|
3859
|
+
publicClient,
|
|
3860
|
+
addresses
|
|
3861
|
+
}) {
|
|
3862
|
+
if (addresses.length === 0) return [];
|
|
3863
|
+
try {
|
|
3864
|
+
const data = await readContract(publicClient, {
|
|
3865
|
+
address: ERC20_BULK_INFO_HELPER_CONTRACT.address,
|
|
3866
|
+
abi: ERC20_BULK_INFO_HELPER_CONTRACT.abi,
|
|
3867
|
+
functionName: "getTokenInfo",
|
|
3868
|
+
args: [addresses]
|
|
3869
|
+
});
|
|
3870
|
+
if (Array.isArray(data) && data.length === addresses.length) return data;
|
|
3871
|
+
} catch {
|
|
3872
|
+
}
|
|
3873
|
+
const results = await Promise.all(
|
|
3874
|
+
addresses.map(async (addr) => {
|
|
3875
|
+
try {
|
|
3876
|
+
const data = await readContract(publicClient, {
|
|
3877
|
+
address: ERC20_BULK_INFO_HELPER_CONTRACT.address,
|
|
3878
|
+
abi: ERC20_BULK_INFO_HELPER_CONTRACT.abi,
|
|
3879
|
+
functionName: "getTokenInfo",
|
|
3880
|
+
args: [[addr]]
|
|
3881
|
+
});
|
|
3882
|
+
if (Array.isArray(data) && data[0]) return data[0];
|
|
3883
|
+
} catch {
|
|
3884
|
+
}
|
|
3885
|
+
return {
|
|
3886
|
+
name: "",
|
|
3887
|
+
symbol: "",
|
|
3888
|
+
decimals: 0,
|
|
3889
|
+
totalSupply: 0n,
|
|
3890
|
+
burnedTokens: 0n
|
|
3891
|
+
};
|
|
3892
|
+
})
|
|
3893
|
+
);
|
|
3894
|
+
return results;
|
|
3895
|
+
}
|
|
3896
|
+
async function fetchAggregateUpvotes({
|
|
3897
|
+
publicClient,
|
|
3898
|
+
tokenAddresses
|
|
3899
|
+
}) {
|
|
3900
|
+
if (tokenAddresses.length === 0) return [];
|
|
3901
|
+
const data = await readContract(publicClient, {
|
|
3902
|
+
address: UPVOTE_APP.address,
|
|
3903
|
+
abi: UPVOTE_APP.abi,
|
|
3904
|
+
functionName: "getUpvotesWithLegacy",
|
|
3905
|
+
args: [
|
|
3906
|
+
tokenAddresses.map((addr) => encodeUpvoteKey(addr)),
|
|
3907
|
+
ALL_STRATEGY_ADDRESSES
|
|
3908
|
+
]
|
|
3909
|
+
});
|
|
3910
|
+
if (!Array.isArray(data)) {
|
|
3911
|
+
throw new Error(
|
|
3912
|
+
"getUpvotesWithLegacy returned non-array; contract or RPC misbehaving"
|
|
3913
|
+
);
|
|
3914
|
+
}
|
|
3915
|
+
return data.map(Number);
|
|
3916
|
+
}
|
|
3917
|
+
function composeAndFilter({
|
|
3918
|
+
tokenAddresses,
|
|
3919
|
+
tokenInfos,
|
|
3920
|
+
pools,
|
|
3921
|
+
upvoteCounts,
|
|
3922
|
+
latestUpvoteTimestamps,
|
|
3923
|
+
wethAddress,
|
|
3924
|
+
usdcAddress,
|
|
3925
|
+
sort,
|
|
3926
|
+
maxTokens,
|
|
3927
|
+
minUpvotes,
|
|
3928
|
+
minMarketCap,
|
|
3929
|
+
recencyHours,
|
|
3930
|
+
nowSec
|
|
3931
|
+
}) {
|
|
3932
|
+
const wethLower = wethAddress.toLowerCase();
|
|
3933
|
+
const usdcLower = usdcAddress?.toLowerCase();
|
|
3934
|
+
let ethPriceInUsdc;
|
|
3935
|
+
if (usdcLower) {
|
|
3936
|
+
const wethUsdcPool = pools.find(
|
|
3937
|
+
(p) => p.tokenAddress.toLowerCase() === wethLower && p.baseTokenAddress.toLowerCase() === usdcLower
|
|
3938
|
+
);
|
|
3939
|
+
const usdcWethPool = pools.find(
|
|
3940
|
+
(p) => p.tokenAddress.toLowerCase() === usdcLower && p.baseTokenAddress.toLowerCase() === wethLower
|
|
3941
|
+
);
|
|
3942
|
+
if (wethUsdcPool?.price) {
|
|
3943
|
+
ethPriceInUsdc = wethUsdcPool.price;
|
|
3944
|
+
} else if (usdcWethPool?.price) {
|
|
3945
|
+
ethPriceInUsdc = 1 / usdcWethPool.price;
|
|
3946
|
+
}
|
|
3947
|
+
}
|
|
3948
|
+
const tokenAddressToPool = /* @__PURE__ */ new Map();
|
|
3949
|
+
for (const pool of pools) {
|
|
3950
|
+
if (pool.baseTokenAddress.toLowerCase() === wethLower) {
|
|
3951
|
+
tokenAddressToPool.set(pool.tokenAddress.toLowerCase(), pool);
|
|
3952
|
+
}
|
|
3953
|
+
}
|
|
3954
|
+
const composed = tokenAddresses.map((address, i) => {
|
|
3955
|
+
const info = tokenInfos[i];
|
|
3956
|
+
const pool = tokenAddressToPool.get(address.toLowerCase());
|
|
3957
|
+
const priceInUsdc = pool?.price && ethPriceInUsdc ? pool.price * ethPriceInUsdc : void 0;
|
|
3958
|
+
let circulating;
|
|
3959
|
+
if (info?.totalSupply) {
|
|
3960
|
+
const burned = info.burnedTokens ?? 0n;
|
|
3961
|
+
const c = info.totalSupply - burned;
|
|
3962
|
+
circulating = c > 0n ? c : 0n;
|
|
3963
|
+
}
|
|
3964
|
+
const decimals = info?.decimals || void 0;
|
|
3965
|
+
const fdv = circulating != null && decimals != null && priceInUsdc != null ? Number(circulating) / 10 ** decimals * priceInUsdc : void 0;
|
|
3966
|
+
return {
|
|
3967
|
+
address,
|
|
3968
|
+
name: info?.name || void 0,
|
|
3969
|
+
symbol: info?.symbol || void 0,
|
|
3970
|
+
decimals,
|
|
3971
|
+
fdv,
|
|
3972
|
+
priceInUsdc,
|
|
3973
|
+
upvotes: upvoteCounts[i] ?? 0,
|
|
3974
|
+
latestUpvoteTimestamp: latestUpvoteTimestamps.get(address.toLowerCase()) ?? 0
|
|
3975
|
+
};
|
|
3976
|
+
});
|
|
3977
|
+
const valid = composed.filter((t) => {
|
|
3978
|
+
if (!t.name?.trim() || !t.symbol?.trim()) return false;
|
|
3979
|
+
const belowFloor = t.fdv == null || t.fdv < minMarketCap;
|
|
3980
|
+
if (belowFloor) {
|
|
3981
|
+
const hoursSince = (nowSec - t.latestUpvoteTimestamp) / 3600;
|
|
3982
|
+
if (hoursSince > recencyHours) return false;
|
|
3983
|
+
}
|
|
3984
|
+
return true;
|
|
3985
|
+
});
|
|
3986
|
+
let sorted;
|
|
3987
|
+
if (sort === "top") {
|
|
3988
|
+
sorted = [...valid].sort((a, b) => b.upvotes - a.upvotes);
|
|
3989
|
+
} else {
|
|
3990
|
+
const byAddr = new Map(valid.map((t) => [t.address.toLowerCase(), t]));
|
|
3991
|
+
sorted = tokenAddresses.map((addr) => byAddr.get(addr.toLowerCase())).filter((t) => t != null);
|
|
3992
|
+
}
|
|
3993
|
+
const qualifies = (t) => t.upvotes >= minUpvotes || t.fdv != null && t.fdv >= minMarketCap;
|
|
3994
|
+
const top = sorted.filter(qualifies);
|
|
3995
|
+
const rest = sorted.filter((t) => !qualifies(t));
|
|
3996
|
+
return [...top, ...rest].slice(0, maxTokens);
|
|
3997
|
+
}
|
|
3998
|
+
var encodePoolKey = (poolKey) => {
|
|
3999
|
+
if (!poolKey || !isValidPoolKey2(poolKey)) {
|
|
4000
|
+
return "0x";
|
|
4001
|
+
}
|
|
4002
|
+
try {
|
|
4003
|
+
return encodeAbiParameters(
|
|
4004
|
+
[
|
|
4005
|
+
{
|
|
4006
|
+
type: "tuple",
|
|
4007
|
+
components: [
|
|
4008
|
+
{ name: "currency0", type: "address" },
|
|
4009
|
+
{ name: "currency1", type: "address" },
|
|
4010
|
+
{ name: "fee", type: "uint24" },
|
|
4011
|
+
{ name: "tickSpacing", type: "int24" },
|
|
4012
|
+
{ name: "hooks", type: "address" }
|
|
4013
|
+
]
|
|
4014
|
+
}
|
|
4015
|
+
],
|
|
4016
|
+
[
|
|
4017
|
+
{
|
|
4018
|
+
currency0: poolKey.currency0,
|
|
4019
|
+
currency1: poolKey.currency1,
|
|
4020
|
+
fee: poolKey.fee,
|
|
4021
|
+
tickSpacing: poolKey.tickSpacing,
|
|
4022
|
+
hooks: poolKey.hooks
|
|
4023
|
+
}
|
|
4024
|
+
]
|
|
4025
|
+
);
|
|
4026
|
+
} catch {
|
|
4027
|
+
return "0x";
|
|
4028
|
+
}
|
|
4029
|
+
};
|
|
4030
|
+
function isValidPoolKey2(poolKey) {
|
|
4031
|
+
return poolKey.fee !== void 0 || poolKey.tickSpacing !== void 0 || poolKey.currency0 !== void 0;
|
|
4032
|
+
}
|
|
4033
|
+
|
|
4034
|
+
export { ALL_STRATEGY_ADDRESSES, DYNAMIC_SPLIT_STRATEGY, ERC20_BULK_INFO_HELPER_CONTRACT, LEGACY_UPVOTE_V1_ADDRESS, LEGACY_UPVOTE_V2_ADDRESS, MULTI_VERSION_UNISWAP_BULK_POOL_FINDER, MULTI_VERSION_UNISWAP_POOL_INFO_RETRIEVER, NULL_ADDRESS, PURE_ALPHA_STRATEGY, SCORE_CONTRACT, SUPPORTED_SCORE_CHAINS, ScoreClient, UNIV234_POOLS_STRATEGY, UPVOTE_APP, UPVOTE_PRICE_ETH, UPVOTE_STORAGE_APP, USER_UPVOTE_CONTRACT, UserUpvoteClient, buildUserUpvote, buildUserUpvoteReceived, calculatePriceFromSqrtPriceX96, calculatePriceInUsdc, calculateUpvoteCost, calculateUserTokenBalance, decodeStrategyMetadata, decodeUpvoteMessage, decodeUpvoteStorageBlob, discoverPools, discoverTokenPool, encodePoolKey, encodeUpvoteKey, extractStrategyAddress, extractTokenAddressFromScoreKey, extractTokenAddressesFromMessages, getFeedContentKey, getScoreKey, getStorageScoreKey, getStorageUpvoteContext, getTokenRankings, getTokenScoreKey, getWethAddress, isDynamicSplitStrategy, isPureAlphaStrategy, isStrategyMessage, isTokenScoreKey, isUniv234PoolsStrategy, isUserUpvoteMessage, parseUserUpvoteMessage, selectStrategy, tokenAddressToUpvoteKeyString, validateUpvoteParams, validateUserUpvoteMessage };
|
|
3599
4035
|
//# sourceMappingURL=index.mjs.map
|
|
3600
4036
|
//# sourceMappingURL=index.mjs.map
|