@net-protocol/score 0.1.7 → 0.1.9
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/dist/index.d.mts +107 -31
- package/dist/index.d.ts +107 -31
- package/dist/index.js +471 -35
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +472 -38
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +11 -3
- package/dist/react.d.ts +11 -3
- package/dist/react.js +744 -0
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +745 -2
- package/dist/react.mjs.map +1 -1
- package/dist/{scoreKeyUtils-D-ONTPej.d.mts → scoreKeyUtils-BQl5oCSc.d.mts} +10 -1
- package/dist/{scoreKeyUtils-D-ONTPej.d.ts → scoreKeyUtils-BQl5oCSc.d.ts} +10 -1
- package/package.json +2 -2
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",
|
|
@@ -2542,6 +2580,10 @@ var USER_UPVOTE_CONTRACT = {
|
|
|
2542
2580
|
address: "0xa4bc2c63dd0157692fd5f409389e5032e37d8895",
|
|
2543
2581
|
abi: user_upvote_default
|
|
2544
2582
|
};
|
|
2583
|
+
var ERC20_BULK_INFO_HELPER_CONTRACT = {
|
|
2584
|
+
address: "0x00000051809cbfacdf7d08ada813836822b880a2",
|
|
2585
|
+
abi: erc20_bulk_info_helper_default
|
|
2586
|
+
};
|
|
2545
2587
|
var encodeUpvoteKey = (tokenAddress) => {
|
|
2546
2588
|
return `0x${BigInt(`0x${tokenAddress.slice(2)}`).toString(16).padStart(64, "0")}`;
|
|
2547
2589
|
};
|
|
@@ -3207,41 +3249,6 @@ var UserUpvoteClient = class {
|
|
|
3207
3249
|
return hash;
|
|
3208
3250
|
}
|
|
3209
3251
|
};
|
|
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
3252
|
var V3_V4_FEE_TIERS = [500, 3e3, 1e4, 12e3, 8388608];
|
|
3246
3253
|
var V4_TICK_SPACINGS = [200];
|
|
3247
3254
|
var V4_HOOKS = [
|
|
@@ -3595,6 +3602,433 @@ async function discoverTokenPool({
|
|
|
3595
3602
|
return results[0] ?? null;
|
|
3596
3603
|
}
|
|
3597
3604
|
|
|
3598
|
-
|
|
3605
|
+
// src/ranking/getTokenRankings.ts
|
|
3606
|
+
var DEFAULT_MESSAGE_SCAN_WINDOW = 150;
|
|
3607
|
+
var DEFAULT_MAX_TOKENS = 50;
|
|
3608
|
+
var DEFAULT_MIN_UPVOTES = 500;
|
|
3609
|
+
var DEFAULT_MIN_MARKET_CAP = 4e4;
|
|
3610
|
+
var DEFAULT_RECENCY_HOURS = 48;
|
|
3611
|
+
var USDC_ADDRESS_BY_CHAIN = {
|
|
3612
|
+
8453: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
|
|
3613
|
+
};
|
|
3614
|
+
var ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
3615
|
+
async function getTokenRankings(options) {
|
|
3616
|
+
const {
|
|
3617
|
+
chainId,
|
|
3618
|
+
sort = "trending",
|
|
3619
|
+
maxTokens = DEFAULT_MAX_TOKENS,
|
|
3620
|
+
messageScanWindow = DEFAULT_MESSAGE_SCAN_WINDOW,
|
|
3621
|
+
rpcUrl
|
|
3622
|
+
} = options;
|
|
3623
|
+
validateChainSupported(chainId);
|
|
3624
|
+
const minUpvotes = options.thresholds?.minUpvotes ?? DEFAULT_MIN_UPVOTES;
|
|
3625
|
+
const minMarketCap = options.thresholds?.minMarketCap ?? DEFAULT_MIN_MARKET_CAP;
|
|
3626
|
+
const recencyHours = options.thresholds?.recencyHours ?? DEFAULT_RECENCY_HOURS;
|
|
3627
|
+
const nowSec = Date.now() / 1e3;
|
|
3628
|
+
const rpcOverride = rpcUrl ? { rpcUrls: Array.isArray(rpcUrl) ? rpcUrl : [rpcUrl] } : void 0;
|
|
3629
|
+
const publicClient = getPublicClient({ chainId, rpcUrl });
|
|
3630
|
+
const netClient = new NetClient({ chainId, overrides: rpcOverride });
|
|
3631
|
+
const messageGroups = await fetchUpvoteMessages({
|
|
3632
|
+
netClient,
|
|
3633
|
+
messageScanWindow
|
|
3634
|
+
});
|
|
3635
|
+
const storageBlobByKey = await fetchStrategyStorage({
|
|
3636
|
+
publicClient,
|
|
3637
|
+
messageGroups
|
|
3638
|
+
});
|
|
3639
|
+
const wethAddress = getWethAddress(chainId);
|
|
3640
|
+
const { tokenAddresses, latestUpvoteTimestamps } = aggregateAndRank({
|
|
3641
|
+
messageGroups,
|
|
3642
|
+
storageBlobByKey,
|
|
3643
|
+
sort,
|
|
3644
|
+
maxTokens,
|
|
3645
|
+
excludeAddresses: [wethAddress.toLowerCase()],
|
|
3646
|
+
nowSec
|
|
3647
|
+
});
|
|
3648
|
+
if (tokenAddresses.length === 0) return [];
|
|
3649
|
+
const usdcAddress = USDC_ADDRESS_BY_CHAIN[chainId];
|
|
3650
|
+
const pairs = [
|
|
3651
|
+
...tokenAddresses.map((tokenAddress) => ({
|
|
3652
|
+
tokenAddress,
|
|
3653
|
+
baseTokenAddress: wethAddress
|
|
3654
|
+
})),
|
|
3655
|
+
...usdcAddress ? [{ tokenAddress: wethAddress, baseTokenAddress: usdcAddress }] : []
|
|
3656
|
+
];
|
|
3657
|
+
const [tokenInfos, pools, upvoteCounts] = await Promise.all([
|
|
3658
|
+
fetchBulkErc20Info({ publicClient, addresses: tokenAddresses }),
|
|
3659
|
+
discoverPools({ publicClient, pairs, chainId }),
|
|
3660
|
+
fetchAggregateUpvotes({ publicClient, tokenAddresses })
|
|
3661
|
+
]);
|
|
3662
|
+
if (tokenInfos.length !== tokenAddresses.length) {
|
|
3663
|
+
throw new Error(
|
|
3664
|
+
`ERC20 bulk info returned ${tokenInfos.length} entries for ${tokenAddresses.length} addresses`
|
|
3665
|
+
);
|
|
3666
|
+
}
|
|
3667
|
+
if (upvoteCounts.length !== tokenAddresses.length) {
|
|
3668
|
+
throw new Error(
|
|
3669
|
+
`getUpvotesWithLegacy returned ${upvoteCounts.length} entries for ${tokenAddresses.length} addresses`
|
|
3670
|
+
);
|
|
3671
|
+
}
|
|
3672
|
+
return composeAndFilter({
|
|
3673
|
+
tokenAddresses,
|
|
3674
|
+
tokenInfos,
|
|
3675
|
+
pools,
|
|
3676
|
+
upvoteCounts,
|
|
3677
|
+
latestUpvoteTimestamps,
|
|
3678
|
+
wethAddress,
|
|
3679
|
+
usdcAddress,
|
|
3680
|
+
sort,
|
|
3681
|
+
maxTokens,
|
|
3682
|
+
minUpvotes,
|
|
3683
|
+
minMarketCap,
|
|
3684
|
+
recencyHours,
|
|
3685
|
+
nowSec
|
|
3686
|
+
});
|
|
3687
|
+
}
|
|
3688
|
+
function validateChainSupported(chainId) {
|
|
3689
|
+
if (!SUPPORTED_SCORE_CHAINS.includes(chainId)) {
|
|
3690
|
+
throw new Error(
|
|
3691
|
+
`getTokenRankings: chainId ${chainId} is not supported. Supported chains: ${SUPPORTED_SCORE_CHAINS.join(", ")}`
|
|
3692
|
+
);
|
|
3693
|
+
}
|
|
3694
|
+
}
|
|
3695
|
+
async function fetchUpvoteMessages({
|
|
3696
|
+
netClient,
|
|
3697
|
+
messageScanWindow
|
|
3698
|
+
}) {
|
|
3699
|
+
const legacyFilter = {
|
|
3700
|
+
appAddress: LEGACY_UPVOTE_V1_ADDRESS,
|
|
3701
|
+
topic: "t"
|
|
3702
|
+
};
|
|
3703
|
+
const strategyFilters = [
|
|
3704
|
+
UNIV234_POOLS_STRATEGY.address,
|
|
3705
|
+
PURE_ALPHA_STRATEGY.address,
|
|
3706
|
+
DYNAMIC_SPLIT_STRATEGY.address
|
|
3707
|
+
].map((stratAddr) => ({
|
|
3708
|
+
appAddress: SCORE_CONTRACT.address,
|
|
3709
|
+
topic: `t${stratAddr.toLowerCase()}`
|
|
3710
|
+
}));
|
|
3711
|
+
const [legacyCount, ...strategyCounts] = await Promise.all([
|
|
3712
|
+
netClient.getMessageCount({ filter: legacyFilter }),
|
|
3713
|
+
...strategyFilters.map((filter) => netClient.getMessageCount({ filter }))
|
|
3714
|
+
]);
|
|
3715
|
+
const sliceRange = (count) => ({
|
|
3716
|
+
startIndex: Math.max(0, count - messageScanWindow),
|
|
3717
|
+
endIndex: count
|
|
3718
|
+
});
|
|
3719
|
+
const [legacy, strategy1, strategy2, strategy3] = await Promise.all([
|
|
3720
|
+
legacyCount > 0 ? netClient.getMessagesBatch({
|
|
3721
|
+
filter: legacyFilter,
|
|
3722
|
+
...sliceRange(legacyCount)
|
|
3723
|
+
}) : Promise.resolve([]),
|
|
3724
|
+
...strategyFilters.map(
|
|
3725
|
+
(filter, i) => strategyCounts[i] > 0 ? netClient.getMessagesBatch({
|
|
3726
|
+
filter,
|
|
3727
|
+
...sliceRange(strategyCounts[i])
|
|
3728
|
+
}) : Promise.resolve([])
|
|
3729
|
+
)
|
|
3730
|
+
]);
|
|
3731
|
+
return { legacy, strategy1, strategy2, strategy3 };
|
|
3732
|
+
}
|
|
3733
|
+
async function fetchStrategyStorage({
|
|
3734
|
+
publicClient,
|
|
3735
|
+
messageGroups
|
|
3736
|
+
}) {
|
|
3737
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3738
|
+
const keys = [];
|
|
3739
|
+
for (const msg of [
|
|
3740
|
+
...messageGroups.strategy1,
|
|
3741
|
+
...messageGroups.strategy2,
|
|
3742
|
+
...messageGroups.strategy3
|
|
3743
|
+
]) {
|
|
3744
|
+
if (!msg.data || !msg.data.startsWith("0x")) continue;
|
|
3745
|
+
const key = msg.data;
|
|
3746
|
+
if (seen.has(key)) continue;
|
|
3747
|
+
seen.add(key);
|
|
3748
|
+
keys.push({ key, operator: SCORE_CONTRACT.address });
|
|
3749
|
+
}
|
|
3750
|
+
if (keys.length === 0) return /* @__PURE__ */ new Map();
|
|
3751
|
+
const results = await readContract(publicClient, {
|
|
3752
|
+
address: STORAGE_CONTRACT.address,
|
|
3753
|
+
abi: STORAGE_CONTRACT.abi,
|
|
3754
|
+
functionName: "bulkGet",
|
|
3755
|
+
args: [keys]
|
|
3756
|
+
});
|
|
3757
|
+
return buildStorageMapFromBulkGetResults(results, keys);
|
|
3758
|
+
}
|
|
3759
|
+
function buildStorageMapFromBulkGetResults(results, keys) {
|
|
3760
|
+
if (results.length !== keys.length) {
|
|
3761
|
+
throw new Error(
|
|
3762
|
+
`bulkGet returned ${results.length} entries for ${keys.length} keys`
|
|
3763
|
+
);
|
|
3764
|
+
}
|
|
3765
|
+
const map = /* @__PURE__ */ new Map();
|
|
3766
|
+
results.forEach((item, idx) => {
|
|
3767
|
+
const value = item?.value;
|
|
3768
|
+
if (value && value !== "0x") {
|
|
3769
|
+
map.set(keys[idx].key, value);
|
|
3770
|
+
}
|
|
3771
|
+
});
|
|
3772
|
+
return map;
|
|
3773
|
+
}
|
|
3774
|
+
function aggregateAndRank({
|
|
3775
|
+
messageGroups,
|
|
3776
|
+
storageBlobByKey,
|
|
3777
|
+
sort,
|
|
3778
|
+
maxTokens,
|
|
3779
|
+
excludeAddresses = [],
|
|
3780
|
+
nowSec
|
|
3781
|
+
}) {
|
|
3782
|
+
const tokenUpvoteEvents = /* @__PURE__ */ new Map();
|
|
3783
|
+
const excludeSet = new Set(excludeAddresses.map((a) => a.toLowerCase()));
|
|
3784
|
+
const addEvent = (tokenAddress, timestamp, count) => {
|
|
3785
|
+
if (!ADDRESS_RE.test(tokenAddress)) return;
|
|
3786
|
+
const lower = tokenAddress.toLowerCase();
|
|
3787
|
+
if (lower === NULL_ADDRESS || excludeSet.has(lower)) return;
|
|
3788
|
+
if (!Number.isFinite(timestamp) || !Number.isFinite(count)) return;
|
|
3789
|
+
const events = tokenUpvoteEvents.get(lower) ?? [];
|
|
3790
|
+
events.push({ timestamp, count });
|
|
3791
|
+
tokenUpvoteEvents.set(lower, events);
|
|
3792
|
+
};
|
|
3793
|
+
for (const msg of messageGroups.legacy) {
|
|
3794
|
+
if (msg.topic !== "t" || !msg.text) continue;
|
|
3795
|
+
let count = 1;
|
|
3796
|
+
if (msg.data && msg.data.startsWith("0x")) {
|
|
3797
|
+
try {
|
|
3798
|
+
const [votes] = decodeAbiParameters(
|
|
3799
|
+
[{ type: "uint256" }],
|
|
3800
|
+
msg.data
|
|
3801
|
+
);
|
|
3802
|
+
count = Number(votes);
|
|
3803
|
+
} catch {
|
|
3804
|
+
count = 1;
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3807
|
+
addEvent(msg.text, Number(msg.timestamp), count);
|
|
3808
|
+
}
|
|
3809
|
+
for (const msg of [
|
|
3810
|
+
...messageGroups.strategy1,
|
|
3811
|
+
...messageGroups.strategy2,
|
|
3812
|
+
...messageGroups.strategy3
|
|
3813
|
+
]) {
|
|
3814
|
+
if (!msg.topic.startsWith("t") || !msg.data || !msg.data.startsWith("0x")) {
|
|
3815
|
+
continue;
|
|
3816
|
+
}
|
|
3817
|
+
const blob = storageBlobByKey.get(msg.data);
|
|
3818
|
+
if (!blob) continue;
|
|
3819
|
+
const decoded = decodeUpvoteStorageBlob(blob);
|
|
3820
|
+
if (!decoded || !decoded.scoreKey) continue;
|
|
3821
|
+
const tokenAddress = extractTokenAddressFromScoreKey(decoded.scoreKey);
|
|
3822
|
+
if (!tokenAddress) continue;
|
|
3823
|
+
addEvent(tokenAddress, Number(msg.timestamp), decoded.scoreDelta);
|
|
3824
|
+
}
|
|
3825
|
+
const timeWeight = (ts) => Math.exp(-0.1 * ((nowSec - ts) / 3600));
|
|
3826
|
+
const latestUpvoteTimestamps = /* @__PURE__ */ new Map();
|
|
3827
|
+
for (const [addr, events] of tokenUpvoteEvents) {
|
|
3828
|
+
let latest = events[0].timestamp;
|
|
3829
|
+
for (const e of events) if (e.timestamp > latest) latest = e.timestamp;
|
|
3830
|
+
latestUpvoteTimestamps.set(addr, latest);
|
|
3831
|
+
}
|
|
3832
|
+
let ordered;
|
|
3833
|
+
if (sort === "top") {
|
|
3834
|
+
ordered = Array.from(tokenUpvoteEvents.keys());
|
|
3835
|
+
} else {
|
|
3836
|
+
const scores = /* @__PURE__ */ new Map();
|
|
3837
|
+
for (const [addr, events] of tokenUpvoteEvents) {
|
|
3838
|
+
if (sort === "recent") {
|
|
3839
|
+
scores.set(addr, latestUpvoteTimestamps.get(addr) ?? 0);
|
|
3840
|
+
} else {
|
|
3841
|
+
const score = events.reduce(
|
|
3842
|
+
(total, e) => total + e.count * timeWeight(e.timestamp),
|
|
3843
|
+
0
|
|
3844
|
+
);
|
|
3845
|
+
scores.set(addr, score);
|
|
3846
|
+
}
|
|
3847
|
+
}
|
|
3848
|
+
ordered = Array.from(scores.entries()).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([address]) => address);
|
|
3849
|
+
}
|
|
3850
|
+
const fetchLimit = Math.max(maxTokens * 3, 30);
|
|
3851
|
+
return {
|
|
3852
|
+
tokenAddresses: ordered.slice(0, fetchLimit),
|
|
3853
|
+
latestUpvoteTimestamps
|
|
3854
|
+
};
|
|
3855
|
+
}
|
|
3856
|
+
async function fetchBulkErc20Info({
|
|
3857
|
+
publicClient,
|
|
3858
|
+
addresses
|
|
3859
|
+
}) {
|
|
3860
|
+
if (addresses.length === 0) return [];
|
|
3861
|
+
try {
|
|
3862
|
+
const data = await readContract(publicClient, {
|
|
3863
|
+
address: ERC20_BULK_INFO_HELPER_CONTRACT.address,
|
|
3864
|
+
abi: ERC20_BULK_INFO_HELPER_CONTRACT.abi,
|
|
3865
|
+
functionName: "getTokenInfo",
|
|
3866
|
+
args: [addresses]
|
|
3867
|
+
});
|
|
3868
|
+
if (Array.isArray(data) && data.length === addresses.length) return data;
|
|
3869
|
+
} catch {
|
|
3870
|
+
}
|
|
3871
|
+
const results = await Promise.all(
|
|
3872
|
+
addresses.map(async (addr) => {
|
|
3873
|
+
try {
|
|
3874
|
+
const data = await readContract(publicClient, {
|
|
3875
|
+
address: ERC20_BULK_INFO_HELPER_CONTRACT.address,
|
|
3876
|
+
abi: ERC20_BULK_INFO_HELPER_CONTRACT.abi,
|
|
3877
|
+
functionName: "getTokenInfo",
|
|
3878
|
+
args: [[addr]]
|
|
3879
|
+
});
|
|
3880
|
+
if (Array.isArray(data) && data[0]) return data[0];
|
|
3881
|
+
} catch {
|
|
3882
|
+
}
|
|
3883
|
+
return {
|
|
3884
|
+
name: "",
|
|
3885
|
+
symbol: "",
|
|
3886
|
+
decimals: 0,
|
|
3887
|
+
totalSupply: 0n,
|
|
3888
|
+
burnedTokens: 0n
|
|
3889
|
+
};
|
|
3890
|
+
})
|
|
3891
|
+
);
|
|
3892
|
+
return results;
|
|
3893
|
+
}
|
|
3894
|
+
async function fetchAggregateUpvotes({
|
|
3895
|
+
publicClient,
|
|
3896
|
+
tokenAddresses
|
|
3897
|
+
}) {
|
|
3898
|
+
if (tokenAddresses.length === 0) return [];
|
|
3899
|
+
const data = await readContract(publicClient, {
|
|
3900
|
+
address: UPVOTE_APP.address,
|
|
3901
|
+
abi: UPVOTE_APP.abi,
|
|
3902
|
+
functionName: "getUpvotesWithLegacy",
|
|
3903
|
+
args: [
|
|
3904
|
+
tokenAddresses.map((addr) => encodeUpvoteKey(addr)),
|
|
3905
|
+
ALL_STRATEGY_ADDRESSES
|
|
3906
|
+
]
|
|
3907
|
+
});
|
|
3908
|
+
if (!Array.isArray(data)) {
|
|
3909
|
+
throw new Error(
|
|
3910
|
+
"getUpvotesWithLegacy returned non-array; contract or RPC misbehaving"
|
|
3911
|
+
);
|
|
3912
|
+
}
|
|
3913
|
+
return data.map(Number);
|
|
3914
|
+
}
|
|
3915
|
+
function composeAndFilter({
|
|
3916
|
+
tokenAddresses,
|
|
3917
|
+
tokenInfos,
|
|
3918
|
+
pools,
|
|
3919
|
+
upvoteCounts,
|
|
3920
|
+
latestUpvoteTimestamps,
|
|
3921
|
+
wethAddress,
|
|
3922
|
+
usdcAddress,
|
|
3923
|
+
sort,
|
|
3924
|
+
maxTokens,
|
|
3925
|
+
minUpvotes,
|
|
3926
|
+
minMarketCap,
|
|
3927
|
+
recencyHours,
|
|
3928
|
+
nowSec
|
|
3929
|
+
}) {
|
|
3930
|
+
const wethLower = wethAddress.toLowerCase();
|
|
3931
|
+
const usdcLower = usdcAddress?.toLowerCase();
|
|
3932
|
+
let ethPriceInUsdc;
|
|
3933
|
+
if (usdcLower) {
|
|
3934
|
+
const wethUsdcPool = pools.find(
|
|
3935
|
+
(p) => p.tokenAddress.toLowerCase() === wethLower && p.baseTokenAddress.toLowerCase() === usdcLower
|
|
3936
|
+
);
|
|
3937
|
+
const usdcWethPool = pools.find(
|
|
3938
|
+
(p) => p.tokenAddress.toLowerCase() === usdcLower && p.baseTokenAddress.toLowerCase() === wethLower
|
|
3939
|
+
);
|
|
3940
|
+
if (wethUsdcPool?.price) {
|
|
3941
|
+
ethPriceInUsdc = wethUsdcPool.price;
|
|
3942
|
+
} else if (usdcWethPool?.price) {
|
|
3943
|
+
ethPriceInUsdc = 1 / usdcWethPool.price;
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
const tokenAddressToPool = /* @__PURE__ */ new Map();
|
|
3947
|
+
for (const pool of pools) {
|
|
3948
|
+
if (pool.baseTokenAddress.toLowerCase() === wethLower) {
|
|
3949
|
+
tokenAddressToPool.set(pool.tokenAddress.toLowerCase(), pool);
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
const composed = tokenAddresses.map((address, i) => {
|
|
3953
|
+
const info = tokenInfos[i];
|
|
3954
|
+
const pool = tokenAddressToPool.get(address.toLowerCase());
|
|
3955
|
+
const priceInUsdc = pool?.price && ethPriceInUsdc ? pool.price * ethPriceInUsdc : void 0;
|
|
3956
|
+
let circulating;
|
|
3957
|
+
if (info?.totalSupply) {
|
|
3958
|
+
const burned = info.burnedTokens ?? 0n;
|
|
3959
|
+
const c = info.totalSupply - burned;
|
|
3960
|
+
circulating = c > 0n ? c : 0n;
|
|
3961
|
+
}
|
|
3962
|
+
const decimals = info?.decimals || void 0;
|
|
3963
|
+
const fdv = circulating != null && decimals != null && priceInUsdc != null ? Number(circulating) / 10 ** decimals * priceInUsdc : void 0;
|
|
3964
|
+
return {
|
|
3965
|
+
address,
|
|
3966
|
+
name: info?.name || void 0,
|
|
3967
|
+
symbol: info?.symbol || void 0,
|
|
3968
|
+
decimals,
|
|
3969
|
+
fdv,
|
|
3970
|
+
priceInUsdc,
|
|
3971
|
+
upvotes: upvoteCounts[i] ?? 0,
|
|
3972
|
+
latestUpvoteTimestamp: latestUpvoteTimestamps.get(address.toLowerCase()) ?? 0
|
|
3973
|
+
};
|
|
3974
|
+
});
|
|
3975
|
+
const valid = composed.filter((t) => {
|
|
3976
|
+
if (!t.name?.trim() || !t.symbol?.trim()) return false;
|
|
3977
|
+
const belowFloor = t.fdv == null || t.fdv < minMarketCap;
|
|
3978
|
+
if (belowFloor) {
|
|
3979
|
+
const hoursSince = (nowSec - t.latestUpvoteTimestamp) / 3600;
|
|
3980
|
+
if (hoursSince > recencyHours) return false;
|
|
3981
|
+
}
|
|
3982
|
+
return true;
|
|
3983
|
+
});
|
|
3984
|
+
let sorted;
|
|
3985
|
+
if (sort === "top") {
|
|
3986
|
+
sorted = [...valid].sort((a, b) => b.upvotes - a.upvotes);
|
|
3987
|
+
} else {
|
|
3988
|
+
const byAddr = new Map(valid.map((t) => [t.address.toLowerCase(), t]));
|
|
3989
|
+
sorted = tokenAddresses.map((addr) => byAddr.get(addr.toLowerCase())).filter((t) => t != null);
|
|
3990
|
+
}
|
|
3991
|
+
const qualifies = (t) => t.upvotes >= minUpvotes || t.fdv != null && t.fdv >= minMarketCap;
|
|
3992
|
+
const top = sorted.filter(qualifies);
|
|
3993
|
+
const rest = sorted.filter((t) => !qualifies(t));
|
|
3994
|
+
return [...top, ...rest].slice(0, maxTokens);
|
|
3995
|
+
}
|
|
3996
|
+
var encodePoolKey = (poolKey) => {
|
|
3997
|
+
if (!poolKey || !isValidPoolKey2(poolKey)) {
|
|
3998
|
+
return "0x";
|
|
3999
|
+
}
|
|
4000
|
+
try {
|
|
4001
|
+
return encodeAbiParameters(
|
|
4002
|
+
[
|
|
4003
|
+
{
|
|
4004
|
+
type: "tuple",
|
|
4005
|
+
components: [
|
|
4006
|
+
{ name: "currency0", type: "address" },
|
|
4007
|
+
{ name: "currency1", type: "address" },
|
|
4008
|
+
{ name: "fee", type: "uint24" },
|
|
4009
|
+
{ name: "tickSpacing", type: "int24" },
|
|
4010
|
+
{ name: "hooks", type: "address" }
|
|
4011
|
+
]
|
|
4012
|
+
}
|
|
4013
|
+
],
|
|
4014
|
+
[
|
|
4015
|
+
{
|
|
4016
|
+
currency0: poolKey.currency0,
|
|
4017
|
+
currency1: poolKey.currency1,
|
|
4018
|
+
fee: poolKey.fee,
|
|
4019
|
+
tickSpacing: poolKey.tickSpacing,
|
|
4020
|
+
hooks: poolKey.hooks
|
|
4021
|
+
}
|
|
4022
|
+
]
|
|
4023
|
+
);
|
|
4024
|
+
} catch {
|
|
4025
|
+
return "0x";
|
|
4026
|
+
}
|
|
4027
|
+
};
|
|
4028
|
+
function isValidPoolKey2(poolKey) {
|
|
4029
|
+
return poolKey.fee !== void 0 || poolKey.tickSpacing !== void 0 || poolKey.currency0 !== void 0;
|
|
4030
|
+
}
|
|
4031
|
+
|
|
4032
|
+
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
4033
|
//# sourceMappingURL=index.mjs.map
|
|
3600
4034
|
//# sourceMappingURL=index.mjs.map
|