@four-meme/four-meme-ai 1.0.6 → 1.0.8
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/CLAUDE.md +91 -91
- package/LICENSE +21 -0
- package/README.md +2 -2
- package/bin/fourmeme.cjs +7 -4
- package/package.json +5 -5
- package/skills/four-meme-integration/SKILL.md +374 -454
- package/skills/four-meme-integration/references/create-token-scripts.md +27 -7
- package/skills/four-meme-integration/references/token-query-api.md +28 -24
- package/skills/four-meme-integration/scripts/8004-balance.ts +52 -52
- package/skills/four-meme-integration/scripts/8004-register.ts +108 -108
- package/skills/four-meme-integration/scripts/execute-buy.ts +198 -198
- package/skills/four-meme-integration/scripts/execute-sell.ts +150 -150
- package/skills/four-meme-integration/scripts/send-token.ts +98 -98
- package/skills/four-meme-integration/scripts/token-list.ts +102 -20
- package/skills/four-meme-integration/scripts/token-rankings.ts +122 -14
|
@@ -1,16 +1,59 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* Four.meme - token rankings (REST API)
|
|
4
|
-
* POST /meme-api/v1/
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* POST /meme-api/v1/public/token/ranking
|
|
5
|
+
*
|
|
6
|
+
* Backward compatible: <orderBy> where orderBy = Time | ProgressDesc | TradingDesc | Hot | Graduated
|
|
7
|
+
* [--barType=HOUR24|HOUR4|HOUR1|MIN30|MIN5] (only for TradingDesc; maps to VOL_* windows)
|
|
8
|
+
*
|
|
9
|
+
* You may also pass a native API RankingType directly: NEW, PROGRESS, VOL_DAY_1, HOT, DEX, VOL, LAST, CAP, …
|
|
10
|
+
*
|
|
11
|
+
* Optional filters: [--pageSize=20] [--symbol=] [--version=] [--rankingKind=]
|
|
12
|
+
* [--minCap=] [--maxCap=] [--minVol=] [--maxVol=] [--minHold=] [--maxHold=]
|
|
13
|
+
*
|
|
14
|
+
* Usage: npx tsx token-rankings.ts <orderOrType> [--barType=HOUR24] [filters...]
|
|
9
15
|
* Output: JSON ranking list.
|
|
10
16
|
*/
|
|
11
17
|
|
|
12
18
|
const API_BASE = 'https://four.meme/meme-api/v1';
|
|
13
19
|
|
|
20
|
+
const LEGACY_ORDER_BY = ['Time', 'ProgressDesc', 'TradingDesc', 'Hot', 'Graduated'] as const;
|
|
21
|
+
|
|
22
|
+
/** Legacy TradingDesc + barType → public ranking `type`. */
|
|
23
|
+
const BAR_TYPE_TO_VOL_TYPE: Record<string, string> = {
|
|
24
|
+
HOUR24: 'VOL_DAY_1',
|
|
25
|
+
DAY1: 'VOL_DAY_1',
|
|
26
|
+
HOUR4: 'VOL_HOUR_4',
|
|
27
|
+
HOUR1: 'VOL_HOUR_1',
|
|
28
|
+
MIN30: 'VOL_MIN_30',
|
|
29
|
+
MIN5: 'VOL_MIN_5',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const LEGACY_TO_TYPE: Record<string, string> = {
|
|
33
|
+
Time: 'NEW',
|
|
34
|
+
ProgressDesc: 'PROGRESS',
|
|
35
|
+
TradingDesc: 'VOL_DAY_1',
|
|
36
|
+
Hot: 'HOT',
|
|
37
|
+
Graduated: 'DEX',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/** Native ranking types allowed as the first argument (aligned with API RankingType). */
|
|
41
|
+
const NATIVE_RANKING_TYPES = new Set([
|
|
42
|
+
'NEW',
|
|
43
|
+
'PROGRESS',
|
|
44
|
+
'VOL_MIN_5',
|
|
45
|
+
'VOL_MIN_30',
|
|
46
|
+
'VOL_HOUR_1',
|
|
47
|
+
'VOL_HOUR_4',
|
|
48
|
+
'VOL_DAY_1',
|
|
49
|
+
'VOL',
|
|
50
|
+
'LAST',
|
|
51
|
+
'HOT',
|
|
52
|
+
'CAP',
|
|
53
|
+
'DEX',
|
|
54
|
+
'BURN',
|
|
55
|
+
]);
|
|
56
|
+
|
|
14
57
|
function parseArg(name: string): string | undefined {
|
|
15
58
|
const prefix = `--${name}=`;
|
|
16
59
|
for (let i = 3; i < process.argv.length; i++) {
|
|
@@ -20,19 +63,84 @@ function parseArg(name: string): string | undefined {
|
|
|
20
63
|
return undefined;
|
|
21
64
|
}
|
|
22
65
|
|
|
66
|
+
function parseNumArg(name: string): number | undefined {
|
|
67
|
+
const v = parseArg(name);
|
|
68
|
+
if (v == null || v.trim() === '') return undefined;
|
|
69
|
+
const n = Number(v);
|
|
70
|
+
return Number.isFinite(n) ? n : undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function resolveRankingType(first: string, barType?: string): string {
|
|
74
|
+
if (first === 'TradingDesc') {
|
|
75
|
+
if (barType && BAR_TYPE_TO_VOL_TYPE[barType]) {
|
|
76
|
+
return BAR_TYPE_TO_VOL_TYPE[barType];
|
|
77
|
+
}
|
|
78
|
+
return 'VOL_DAY_1';
|
|
79
|
+
}
|
|
80
|
+
if (LEGACY_TO_TYPE[first]) {
|
|
81
|
+
return LEGACY_TO_TYPE[first];
|
|
82
|
+
}
|
|
83
|
+
return first;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function normalizeLegacyOrderBy(s: string): string {
|
|
87
|
+
const map: Record<string, string> = {
|
|
88
|
+
time: 'Time',
|
|
89
|
+
progressdesc: 'ProgressDesc',
|
|
90
|
+
tradingdesc: 'TradingDesc',
|
|
91
|
+
hot: 'Hot',
|
|
92
|
+
graduated: 'Graduated',
|
|
93
|
+
};
|
|
94
|
+
return map[s.toLowerCase()] ?? s;
|
|
95
|
+
}
|
|
96
|
+
|
|
23
97
|
async function main() {
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
if (!
|
|
27
|
-
console.error(
|
|
28
|
-
|
|
98
|
+
const rawFirst = process.argv[2];
|
|
99
|
+
const first = rawFirst ? normalizeLegacyOrderBy(rawFirst) : '';
|
|
100
|
+
if (!first) {
|
|
101
|
+
console.error(
|
|
102
|
+
'Usage: npx tsx token-rankings.ts <orderBy|RankingType> [--barType=HOUR24] [--pageSize=20] ...',
|
|
103
|
+
);
|
|
104
|
+
console.error(
|
|
105
|
+
'Legacy orderBy: Time | ProgressDesc | TradingDesc | Hot | Graduated (barType for TradingDesc)',
|
|
106
|
+
);
|
|
107
|
+
console.error('Or native type: NEW, PROGRESS, VOL_DAY_1, HOT, DEX, VOL, LAST, CAP, BURN, ...');
|
|
29
108
|
process.exit(1);
|
|
30
109
|
}
|
|
31
|
-
|
|
110
|
+
|
|
32
111
|
const barType = parseArg('barType');
|
|
33
|
-
|
|
112
|
+
let rankingType = resolveRankingType(first, barType);
|
|
113
|
+
|
|
114
|
+
const isLegacy = (LEGACY_ORDER_BY as readonly string[]).includes(first);
|
|
115
|
+
if (!isLegacy && !NATIVE_RANKING_TYPES.has(rankingType)) {
|
|
116
|
+
console.error(`Unknown ranking type: ${first}`);
|
|
117
|
+
console.error(
|
|
118
|
+
`Use legacy: ${LEGACY_ORDER_BY.join(' | ')} or native: ${[...NATIVE_RANKING_TYPES].join(', ')}`,
|
|
119
|
+
);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const pageSizeArg = parseNumArg('pageSize');
|
|
124
|
+
const pageSize = pageSizeArg != null ? Math.min(100, Math.max(1, pageSizeArg)) : 20;
|
|
125
|
+
|
|
126
|
+
const body: Record<string, unknown> = {
|
|
127
|
+
type: rankingType,
|
|
128
|
+
pageSize,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const symbol = parseArg('symbol')?.trim();
|
|
132
|
+
if (symbol) body.symbol = symbol;
|
|
133
|
+
const version = parseArg('version')?.trim();
|
|
134
|
+
if (version) body.version = version;
|
|
135
|
+
const rankingKind = parseArg('rankingKind')?.trim();
|
|
136
|
+
if (rankingKind) body.rankingKind = rankingKind;
|
|
137
|
+
|
|
138
|
+
for (const key of ['minCap', 'maxCap', 'minVol', 'maxVol', 'minHold', 'maxHold'] as const) {
|
|
139
|
+
const n = parseNumArg(key);
|
|
140
|
+
if (n !== undefined) body[key] = n;
|
|
141
|
+
}
|
|
34
142
|
|
|
35
|
-
const url = `${API_BASE}/
|
|
143
|
+
const url = `${API_BASE}/public/token/ranking`;
|
|
36
144
|
const res = await fetch(url, {
|
|
37
145
|
method: 'POST',
|
|
38
146
|
headers: {
|
|
@@ -42,7 +150,7 @@ async function main() {
|
|
|
42
150
|
body: JSON.stringify(body),
|
|
43
151
|
});
|
|
44
152
|
if (!res.ok) {
|
|
45
|
-
throw new Error(`token/
|
|
153
|
+
throw new Error(`token/ranking failed: ${res.status} ${await res.text()}`);
|
|
46
154
|
}
|
|
47
155
|
const data = await res.json();
|
|
48
156
|
console.log(JSON.stringify(data, null, 2));
|