@four-meme/four-meme-ai 1.0.0

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.
Files changed (34) hide show
  1. package/CLAUDE.md +91 -0
  2. package/README.md +79 -0
  3. package/bin/fourmeme.cjs +124 -0
  4. package/openclaw.plugin.json +11 -0
  5. package/package.json +55 -0
  6. package/plugin.ts +7 -0
  7. package/skills/four-meme-integration/SKILL.md +432 -0
  8. package/skills/four-meme-integration/references/api-create-token.md +55 -0
  9. package/skills/four-meme-integration/references/contract-addresses.md +34 -0
  10. package/skills/four-meme-integration/references/create-token-scripts.md +63 -0
  11. package/skills/four-meme-integration/references/errors.md +27 -0
  12. package/skills/four-meme-integration/references/event-listening.md +75 -0
  13. package/skills/four-meme-integration/references/execute-trade.md +31 -0
  14. package/skills/four-meme-integration/references/tax-token-query.md +38 -0
  15. package/skills/four-meme-integration/references/token-query-api.md +40 -0
  16. package/skills/four-meme-integration/references/token-tax-info.md +77 -0
  17. package/skills/four-meme-integration/scripts/8004-balance.ts +52 -0
  18. package/skills/four-meme-integration/scripts/8004-register.ts +108 -0
  19. package/skills/four-meme-integration/scripts/create-token-api.ts +251 -0
  20. package/skills/four-meme-integration/scripts/create-token-chain.ts +85 -0
  21. package/skills/four-meme-integration/scripts/execute-buy.ts +198 -0
  22. package/skills/four-meme-integration/scripts/execute-sell.ts +150 -0
  23. package/skills/four-meme-integration/scripts/get-public-config.ts +25 -0
  24. package/skills/four-meme-integration/scripts/get-recent-events.ts +76 -0
  25. package/skills/four-meme-integration/scripts/get-tax-token-info.ts +69 -0
  26. package/skills/four-meme-integration/scripts/get-token-info.ts +94 -0
  27. package/skills/four-meme-integration/scripts/quote-buy.ts +85 -0
  28. package/skills/four-meme-integration/scripts/quote-sell.ts +66 -0
  29. package/skills/four-meme-integration/scripts/send-token.ts +98 -0
  30. package/skills/four-meme-integration/scripts/token-get.ts +31 -0
  31. package/skills/four-meme-integration/scripts/token-list.ts +52 -0
  32. package/skills/four-meme-integration/scripts/token-rankings.ts +54 -0
  33. package/skills/four-meme-integration/scripts/verify-events.ts +47 -0
  34. package/tsconfig.json +15 -0
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Four.meme - buy quote via TokenManagerHelper3.tryBuy (BSC only).
4
+ * Usage: npx tsx quote-buy.ts <tokenAddress> <amountWei> [fundsWei]
5
+ */
6
+
7
+ import { createPublicClient, http } from 'viem';
8
+ import { bsc } from 'viem/chains';
9
+
10
+ const HELPER_ADDRESS = '0xF251F83e40a78868FcfA3FA4599Dad6494E46034' as const;
11
+
12
+ const HELPER_ABI = [
13
+ {
14
+ name: 'tryBuy',
15
+ type: 'function',
16
+ stateMutability: 'view',
17
+ inputs: [
18
+ { name: 'token', type: 'address' },
19
+ { name: 'amount', type: 'uint256' },
20
+ { name: 'funds', type: 'uint256' },
21
+ ],
22
+ outputs: [
23
+ { name: 'tokenManager', type: 'address' },
24
+ { name: 'quote', type: 'address' },
25
+ { name: 'estimatedAmount', type: 'uint256' },
26
+ { name: 'estimatedCost', type: 'uint256' },
27
+ { name: 'estimatedFee', type: 'uint256' },
28
+ { name: 'amountMsgValue', type: 'uint256' },
29
+ { name: 'amountApproval', type: 'uint256' },
30
+ { name: 'amountFunds', type: 'uint256' },
31
+ ],
32
+ },
33
+ ] as const;
34
+
35
+ const RPC_URL = process.env.BSC_RPC_URL || 'https://bsc-dataseed.binance.org';
36
+
37
+ async function main() {
38
+ const tokenAddress = process.argv[2] as `0x${string}`;
39
+ const amountWei = BigInt(process.argv[3] ?? '0');
40
+ const fundsWei = BigInt(process.argv[4] ?? '0');
41
+
42
+ if (!tokenAddress) {
43
+ console.error('Usage: npx tsx quote-buy.ts <tokenAddress> <amountWei> [fundsWei]');
44
+ console.error('BSC only. amountWei: token amount (0 for funds-based); fundsWei: quote to spend (0 for amount-based)');
45
+ process.exit(1);
46
+ }
47
+
48
+ const client = createPublicClient({
49
+ chain: bsc,
50
+ transport: http(RPC_URL),
51
+ });
52
+
53
+ const [
54
+ tokenManager,
55
+ quote,
56
+ estimatedAmount,
57
+ estimatedCost,
58
+ estimatedFee,
59
+ amountMsgValue,
60
+ amountApproval,
61
+ amountFunds,
62
+ ] = await client.readContract({
63
+ address: HELPER_ADDRESS,
64
+ abi: HELPER_ABI,
65
+ functionName: 'tryBuy',
66
+ args: [tokenAddress, amountWei, fundsWei],
67
+ });
68
+
69
+ const out = {
70
+ tokenManager,
71
+ quote: quote === '0x0000000000000000000000000000000000000000' ? 'native' : quote,
72
+ estimatedAmount: estimatedAmount.toString(),
73
+ estimatedCost: estimatedCost.toString(),
74
+ estimatedFee: estimatedFee.toString(),
75
+ amountMsgValue: amountMsgValue.toString(),
76
+ amountApproval: amountApproval.toString(),
77
+ amountFunds: amountFunds.toString(),
78
+ };
79
+ console.log(JSON.stringify(out, null, 2));
80
+ }
81
+
82
+ main().catch((e) => {
83
+ console.error(e.message || e);
84
+ process.exit(1);
85
+ });
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Four.meme - sell quote via TokenManagerHelper3.trySell (BSC only).
4
+ * Usage: npx tsx quote-sell.ts <tokenAddress> <amountWei>
5
+ */
6
+
7
+ import { createPublicClient, http } from 'viem';
8
+ import { bsc } from 'viem/chains';
9
+
10
+ const HELPER_ADDRESS = '0xF251F83e40a78868FcfA3FA4599Dad6494E46034' as const;
11
+
12
+ const HELPER_ABI = [
13
+ {
14
+ name: 'trySell',
15
+ type: 'function',
16
+ stateMutability: 'view',
17
+ inputs: [
18
+ { name: 'token', type: 'address' },
19
+ { name: 'amount', type: 'uint256' },
20
+ ],
21
+ outputs: [
22
+ { name: 'tokenManager', type: 'address' },
23
+ { name: 'quote', type: 'address' },
24
+ { name: 'funds', type: 'uint256' },
25
+ { name: 'fee', type: 'uint256' },
26
+ ],
27
+ },
28
+ ] as const;
29
+
30
+ const RPC_URL = process.env.BSC_RPC_URL || 'https://bsc-dataseed.binance.org';
31
+
32
+ async function main() {
33
+ const tokenAddress = process.argv[2] as `0x${string}`;
34
+ const amountWei = BigInt(process.argv[3] ?? '0');
35
+
36
+ if (!tokenAddress) {
37
+ console.error('Usage: npx tsx quote-sell.ts <tokenAddress> <amountWei>');
38
+ console.error('BSC only.');
39
+ process.exit(1);
40
+ }
41
+
42
+ const client = createPublicClient({
43
+ chain: bsc,
44
+ transport: http(RPC_URL),
45
+ });
46
+
47
+ const [tokenManager, quote, funds, fee] = await client.readContract({
48
+ address: HELPER_ADDRESS,
49
+ abi: HELPER_ABI,
50
+ functionName: 'trySell',
51
+ args: [tokenAddress, amountWei],
52
+ });
53
+
54
+ const out = {
55
+ tokenManager,
56
+ quote: quote === '0x0000000000000000000000000000000000000000' ? 'native' : quote,
57
+ funds: funds.toString(),
58
+ fee: fee.toString(),
59
+ };
60
+ console.log(JSON.stringify(out, null, 2));
61
+ }
62
+
63
+ main().catch((e) => {
64
+ console.error(e.message || e);
65
+ process.exit(1);
66
+ });
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Four.meme - send BNB or ERC20 from current wallet to a target address (BSC).
4
+ *
5
+ * Usage:
6
+ * npx tsx send-token.ts <toAddress> <amountWei> [tokenAddress]
7
+ * - toAddress: recipient wallet address (0x...)
8
+ * - amountWei: amount in wei (for BNB or token decimals)
9
+ * - tokenAddress: optional; omit or use "BNB" / "0x0" for native BNB; otherwise ERC20 token contract address
10
+ *
11
+ * Env: PRIVATE_KEY or FOURMEME_PRIVATE_KEY. Optional: BSC_RPC_URL.
12
+ */
13
+
14
+ import { createWalletClient, http, parseAbi } from 'viem';
15
+ import { privateKeyToAccount } from 'viem/accounts';
16
+ import { bsc } from 'viem/chains';
17
+
18
+ const ZERO = '0x0000000000000000000000000000000000000000' as const;
19
+
20
+ const ERC20_ABI = parseAbi([
21
+ 'function transfer(address to, uint256 amount) returns (bool)',
22
+ ]);
23
+
24
+ function isAddress(s: string): boolean {
25
+ return /^0x[0-9a-fA-F]{40}$/.test(s);
26
+ }
27
+
28
+ async function main() {
29
+ const privateKey = process.env.PRIVATE_KEY || process.env.FOURMEME_PRIVATE_KEY;
30
+ if (!privateKey) {
31
+ console.error('Set PRIVATE_KEY or FOURMEME_PRIVATE_KEY');
32
+ process.exit(1);
33
+ }
34
+ const pk = privateKey.startsWith('0x') ? (privateKey as `0x${string}`) : (`0x${privateKey}` as `0x${string}`);
35
+ const account = privateKeyToAccount(pk);
36
+
37
+ const toAddress = process.argv[2];
38
+ const amountWeiRaw = process.argv[3];
39
+ const tokenAddress = process.argv[4]; // optional: BNB if omitted or "BNB" or 0x0
40
+
41
+ if (!toAddress || !amountWeiRaw) {
42
+ console.error('Usage: send-token.ts <toAddress> <amountWei> [tokenAddress]');
43
+ console.error(' toAddress: recipient 0x... address');
44
+ console.error(' amountWei: amount in wei (for BNB or token smallest unit)');
45
+ console.error(' tokenAddress: optional; omit or BNB/0x0 = native BNB; else ERC20 contract address');
46
+ process.exit(1);
47
+ }
48
+ if (!isAddress(toAddress)) {
49
+ console.error('Invalid toAddress:', toAddress);
50
+ process.exit(1);
51
+ }
52
+
53
+ const amountWei = BigInt(amountWeiRaw);
54
+ if (amountWei <= 0n) {
55
+ console.error('amountWei must be positive');
56
+ process.exit(1);
57
+ }
58
+
59
+ const isNative =
60
+ !tokenAddress ||
61
+ tokenAddress.toUpperCase() === 'BNB' ||
62
+ tokenAddress === ZERO ||
63
+ tokenAddress.toLowerCase() === '0x0000000000000000000000000000000000000000';
64
+
65
+ const rpcUrl = process.env.BSC_RPC_URL || 'https://bsc-dataseed.binance.org';
66
+ const client = createWalletClient({
67
+ account,
68
+ chain: bsc,
69
+ transport: http(rpcUrl),
70
+ });
71
+
72
+ let txHash: `0x${string}`;
73
+
74
+ if (isNative) {
75
+ txHash = await client.sendTransaction({
76
+ to: toAddress as `0x${string}`,
77
+ value: amountWei,
78
+ });
79
+ } else {
80
+ if (!isAddress(tokenAddress)) {
81
+ console.error('Invalid tokenAddress:', tokenAddress);
82
+ process.exit(1);
83
+ }
84
+ txHash = await client.writeContract({
85
+ address: tokenAddress as `0x${string}`,
86
+ abi: ERC20_ABI,
87
+ functionName: 'transfer',
88
+ args: [toAddress as `0x${string}`, amountWei],
89
+ });
90
+ }
91
+
92
+ console.log(JSON.stringify({ txHash, to: toAddress, amountWei: amountWei.toString(), native: isNative }, null, 2));
93
+ }
94
+
95
+ main().catch((e) => {
96
+ console.error(e.message || e);
97
+ process.exit(1);
98
+ });
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Four.meme - token detail + trading info (REST API)
4
+ * GET /meme-api/v1/private/token/get/v2?address=<address>
5
+ * Usage: npx tsx token-get.ts <tokenAddress>
6
+ * Output: JSON token info and trading info.
7
+ */
8
+
9
+ const API_BASE = 'https://four.meme/meme-api/v1';
10
+
11
+ async function main() {
12
+ const address = process.argv[2];
13
+ if (!address) {
14
+ console.error('Usage: npx tsx token-get.ts <tokenAddress>');
15
+ process.exit(1);
16
+ }
17
+ const url = `${API_BASE}/private/token/get/v2?address=${encodeURIComponent(address)}`;
18
+ const res = await fetch(url, {
19
+ headers: { Accept: 'application/json' },
20
+ });
21
+ if (!res.ok) {
22
+ throw new Error(`token/get/v2 failed: ${res.status} ${await res.text()}`);
23
+ }
24
+ const data = await res.json();
25
+ console.log(JSON.stringify(data, null, 2));
26
+ }
27
+
28
+ main().catch((e) => {
29
+ console.error(e.message || e);
30
+ process.exit(1);
31
+ });
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Four.meme - token list (REST API)
4
+ * GET /meme-api/v1/private/token/query
5
+ * Usage: npx tsx token-list.ts [--orderBy=Hot] [--pageIndex=1] [--pageSize=30] [--tokenName=] [--symbol=] [--labels=] [--listedPancake=false]
6
+ * Output: JSON list of tokens.
7
+ */
8
+
9
+ const API_BASE = 'https://four.meme/meme-api/v1';
10
+
11
+ function parseArg(name: string, defaultValue: string): string {
12
+ const prefix = `--${name}=`;
13
+ for (let i = 2; i < process.argv.length; i++) {
14
+ const arg = process.argv[i];
15
+ if (arg.startsWith(prefix)) return arg.slice(prefix.length);
16
+ }
17
+ return defaultValue;
18
+ }
19
+
20
+ async function main() {
21
+ const orderBy = parseArg('orderBy', 'Hot');
22
+ const tokenName = parseArg('tokenName', '');
23
+ const listedPancake = parseArg('listedPancake', 'false');
24
+ const pageIndex = parseArg('pageIndex', '1');
25
+ const pageSize = parseArg('pageSize', '30');
26
+ const symbol = parseArg('symbol', '');
27
+ const labels = parseArg('labels', '');
28
+
29
+ const params = new URLSearchParams({
30
+ orderBy,
31
+ tokenName,
32
+ listedPancake,
33
+ pageIndex,
34
+ pageSize,
35
+ symbol,
36
+ labels,
37
+ });
38
+ const url = `${API_BASE}/private/token/query?${params.toString()}`;
39
+ const res = await fetch(url, {
40
+ headers: { Accept: 'application/json' },
41
+ });
42
+ if (!res.ok) {
43
+ throw new Error(`token/query failed: ${res.status} ${await res.text()}`);
44
+ }
45
+ const data = await res.json();
46
+ console.log(JSON.stringify(data, null, 2));
47
+ }
48
+
49
+ main().catch((e) => {
50
+ console.error(e.message || e);
51
+ process.exit(1);
52
+ });
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Four.meme - token rankings (REST API)
4
+ * POST /meme-api/v1/private/token/query/advanced
5
+ * Body: { orderBy: "Time"|"ProgressDesc"|"TradingDesc"|"Hot"|"Graduated" [, barType: "HOUR24" ] }
6
+ * Usage: npx tsx token-rankings.ts <orderBy> [--barType=HOUR24]
7
+ * orderBy: Time | ProgressDesc | TradingDesc | Hot | Graduated
8
+ * --barType only for TradingDesc (24h volume)
9
+ * Output: JSON ranking list.
10
+ */
11
+
12
+ const API_BASE = 'https://four.meme/meme-api/v1';
13
+
14
+ function parseArg(name: string): string | undefined {
15
+ const prefix = `--${name}=`;
16
+ for (let i = 3; i < process.argv.length; i++) {
17
+ const arg = process.argv[i];
18
+ if (arg.startsWith(prefix)) return arg.slice(prefix.length);
19
+ }
20
+ return undefined;
21
+ }
22
+
23
+ async function main() {
24
+ const orderBy = process.argv[2];
25
+ const validOrderBy = ['Time', 'ProgressDesc', 'TradingDesc', 'Hot', 'Graduated'];
26
+ if (!orderBy || !validOrderBy.includes(orderBy)) {
27
+ console.error('Usage: npx tsx token-rankings.ts <orderBy> [--barType=HOUR24]');
28
+ console.error('orderBy: Time | ProgressDesc | TradingDesc | Hot | Graduated');
29
+ process.exit(1);
30
+ }
31
+ const body: Record<string, string> = { orderBy };
32
+ const barType = parseArg('barType');
33
+ if (barType) body.barType = barType;
34
+
35
+ const url = `${API_BASE}/private/token/query/advanced`;
36
+ const res = await fetch(url, {
37
+ method: 'POST',
38
+ headers: {
39
+ Accept: 'application/json',
40
+ 'Content-Type': 'application/json',
41
+ },
42
+ body: JSON.stringify(body),
43
+ });
44
+ if (!res.ok) {
45
+ throw new Error(`token/query/advanced failed: ${res.status} ${await res.text()}`);
46
+ }
47
+ const data = await res.json();
48
+ console.log(JSON.stringify(data, null, 2));
49
+ }
50
+
51
+ main().catch((e) => {
52
+ console.error(e.message || e);
53
+ process.exit(1);
54
+ });
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Verification helper: fetch TokenManager2 events for the last N blocks on BSC.
4
+ * Usage: npx tsx verify-events.ts [blockCount]
5
+ * Default blockCount 50. No private key or tx, read-only.
6
+ */
7
+
8
+ import { createPublicClient, http, parseAbiItem } from 'viem';
9
+ import { bsc } from 'viem/chains';
10
+
11
+ const TOKEN_MANAGER2_BSC = '0x5c952063c7fc8610FFDB798152D69F0B9550762b' as const;
12
+ const EVENTS = [
13
+ parseAbiItem(
14
+ 'event TokenCreate(address creator, address token, uint256 requestId, string name, string symbol, uint256 totalSupply, uint256 launchTime, uint256 launchFee)'
15
+ ),
16
+ parseAbiItem(
17
+ 'event TokenPurchase(address token, address account, uint256 price, uint256 amount, uint256 cost, uint256 fee, uint256 offers, uint256 funds)'
18
+ ),
19
+ parseAbiItem(
20
+ 'event TokenSale(address token, address account, uint256 price, uint256 amount, uint256 cost, uint256 fee, uint256 offers, uint256 funds)'
21
+ ),
22
+ parseAbiItem('event LiquidityAdded(address base, uint256 offers, address quote, uint256 funds)'),
23
+ ];
24
+
25
+ async function main() {
26
+ const blockCount = parseInt(process.argv[2] ?? '50', 10) || 50;
27
+ const rpcUrl = process.env.BSC_RPC_URL || 'https://bsc-dataseed.binance.org';
28
+ const client = createPublicClient({
29
+ chain: bsc,
30
+ transport: http(rpcUrl),
31
+ });
32
+ const block = await client.getBlockNumber();
33
+ const fromBlock = block - BigInt(blockCount);
34
+ const toBlock = block;
35
+ const logs = await client.getLogs({
36
+ address: TOKEN_MANAGER2_BSC,
37
+ events: EVENTS,
38
+ fromBlock: fromBlock < 0n ? 0n : fromBlock,
39
+ toBlock,
40
+ });
41
+ console.log(JSON.stringify({ fromBlock: String(fromBlock), toBlock: String(toBlock), count: logs.length, events: logs.map((l) => ({ eventName: l.eventName, blockNumber: Number(l.blockNumber), args: l.args })) }, null, 2));
42
+ }
43
+
44
+ main().catch((e) => {
45
+ console.error(e.message || e);
46
+ process.exit(1);
47
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "outDir": "dist",
10
+ "rootDir": ".",
11
+ "types": ["node"]
12
+ },
13
+ "include": ["skills/**/*.ts"],
14
+ "exclude": ["node_modules", "dist"]
15
+ }